Skip to content

Commit

Permalink
Processor improvements (#3101)
Browse files Browse the repository at this point in the history
Relax restrictions for Write-Error.
Log PowerShell's error stream with verbose level.
Create new exception for the case when the same module version exists in different module paths.
  • Loading branch information
msftrubengu authored Mar 23, 2023
1 parent cda7a08 commit 0d54209
Show file tree
Hide file tree
Showing 12 changed files with 364 additions and 179 deletions.
2 changes: 1 addition & 1 deletion src/AppInstallerSharedLib/Public/AppInstallerErrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@
#define WINGET_CONFIG_ERROR_UNIT_INVOKE_GET ((HRESULT)0x8A15C104)
#define WINGET_CONFIG_ERROR_UNIT_INVOKE_TEST ((HRESULT)0x8A15C105)
#define WINGET_CONFIG_ERROR_UNIT_INVOKE_SET ((HRESULT)0x8A15C106)

#define WINGET_CONFIG_ERROR_UNIT_MODULE_CONFLICT ((HRESULT)0x8A15C107)

namespace AppInstaller
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ namespace Microsoft.Management.Configuration.Processor.DscModule
using System.Collections.ObjectModel;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using Microsoft.Management.Configuration.Processor.DscResourcesInfo;
using Microsoft.Management.Configuration.Processor.Exceptions;
using Microsoft.Management.Configuration.Processor.Extensions;
using Microsoft.Management.Configuration.Processor.Helpers;
using Microsoft.PowerShell.Commands;
using Windows.Foundation.Collections;
Expand Down Expand Up @@ -54,51 +52,26 @@ public DscModuleV2()
public string InvokeDscResourceCmd { get; } = Commands.InvokeDscResource;

/// <inheritdoc/>
public IReadOnlyList<DscResourceInfoInternal> GetAllDscResources(Runspace runspace)
public IReadOnlyList<DscResourceInfoInternal> GetAllDscResources(PowerShell pwsh)
{
var result = new List<DscResourceInfoInternal>();

using PowerShell pwsh = PowerShell.Create(runspace);
var resources = pwsh.AddCommand(this.GetDscResourceCmd)
.InvokeAndStopOnError();

return this.ConvertToDscResourceInfoInternal(resources);
return this.GetDscResources(pwsh, null, null);
}

/// <inheritdoc/>
public IReadOnlyList<DscResourceInfoInternal> GetDscResourcesInModule(
Runspace runspace,
PowerShell pwsh,
ModuleSpecification moduleSpecification)
{
var result = new List<DscResourceInfoInternal>();

using PowerShell pwsh = PowerShell.Create(runspace);

var resources = pwsh.AddCommand(this.GetDscResourceCmd)
.AddParameter(Parameters.Module, moduleSpecification)
.InvokeAndStopOnError();

return this.ConvertToDscResourceInfoInternal(resources);
return this.GetDscResources(pwsh, null, moduleSpecification);
}

/// <inheritdoc/>
public DscResourceInfoInternal? GetDscResource(
Runspace runspace,
PowerShell pwsh,
string name,
ModuleSpecification? moduleSpecification)
{
using PowerShell pwsh = PowerShell.Create(runspace);
pwsh.AddCommand(this.GetDscResourceCmd)
.AddParameter(Parameters.Name, name);

if (moduleSpecification is not null)
{
pwsh.AddParameter(Parameters.Module, moduleSpecification);
}

var resources = pwsh.InvokeAndStopOnError();

var dscResourceInfos = this.ConvertToDscResourceInfoInternal(resources);
var dscResourceInfos = this.GetDscResources(pwsh, name, moduleSpecification);

if (dscResourceInfos.Count == 0)
{
Expand All @@ -114,17 +87,15 @@ public IReadOnlyList<DscResourceInfoInternal> GetDscResourcesInModule(

/// <inheritdoc/>
public ValueSet InvokeGetResource(
Runspace runspace,
PowerShell pwsh,
ValueSet settings,
string name,
ModuleSpecification? moduleSpecification)
{
using PowerShell pwsh = PowerShell.Create(runspace);

var getResult = pwsh.AddCommand(this.InvokeDscResourceCmd)
.AddParameters(PrepareInvokeParameters(name, settings, moduleSpecification))
.AddParameter(Parameters.Method, DscMethods.Get)
.InvokeAndStopOnError()
.Invoke()
.FirstOrDefault();

if (getResult is null)
Expand All @@ -151,19 +122,17 @@ public ValueSet InvokeGetResource(

/// <inheritdoc/>
public bool InvokeTestResource(
Runspace runspace,
PowerShell pwsh,
ValueSet settings,
string name,
ModuleSpecification? moduleSpecification)
{
using PowerShell pwsh = PowerShell.Create(runspace);

// Returned type is InvokeDscResourceTestResult which is a PowerShell classed defined
// in PSDesiredStateConfiguration.psm1.
dynamic? testResult = pwsh.AddCommand(this.InvokeDscResourceCmd)
.AddParameters(PrepareInvokeParameters(name, settings, moduleSpecification))
.AddParameter(Parameters.Method, DscMethods.Test)
.InvokeAndStopOnError()
.Invoke()
.FirstOrDefault();

if (testResult is null ||
Expand All @@ -177,19 +146,17 @@ public bool InvokeTestResource(

/// <inheritdoc/>
public bool InvokeSetResource(
Runspace runspace,
PowerShell pwsh,
ValueSet settings,
string name,
ModuleSpecification? moduleSpecification)
{
using PowerShell pwsh = PowerShell.Create(runspace);

// Returned type is InvokeDscResourceSetResult which is a PowerShell classed defined
// in PSDesiredStateConfiguration.psm1.
dynamic? setResult = pwsh.AddCommand(this.InvokeDscResourceCmd)
.AddParameters(PrepareInvokeParameters(name, settings, moduleSpecification))
.AddParameter(Parameters.Method, DscMethods.Set)
.InvokeAndStopOnError()
.Invoke()
.FirstOrDefault();

if (setResult is null ||
Expand Down Expand Up @@ -226,6 +193,40 @@ private static Dictionary<string, object> PrepareInvokeParameters(
return parameters;
}

private IReadOnlyList<DscResourceInfoInternal> GetDscResources(
PowerShell pwsh,
string? name,
ModuleSpecification? moduleSpecification)
{
pwsh.AddCommand(this.GetDscResourceCmd);

if (name is not null)
{
pwsh.AddParameter(Parameters.Name, name);
}

if (moduleSpecification is not null)
{
pwsh.AddParameter(Parameters.Module, moduleSpecification);
}

try
{
var resources = pwsh.Invoke();
return this.ConvertToDscResourceInfoInternal(resources);
}
catch (RuntimeException e)
{
// Detect easily this.
if (e.ErrorRecord.FullyQualifiedErrorId == "ExceptionWhenSetting,GetResourceFromKeyword")
{
throw new GetDscResourceModuleConflict(name, moduleSpecification, e);
}

throw;
}
}

private List<DscResourceInfoInternal> ConvertToDscResourceInfoInternal(Collection<PSObject> psObjects)
{
var result = new List<DscResourceInfoInternal>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace Microsoft.Management.Configuration.Processor.DscModule
{
using System.Collections.Generic;
using System.Management.Automation.Runspaces;
using System.Management.Automation;
using Microsoft.Management.Configuration.Processor.DscResourcesInfo;
using Microsoft.PowerShell.Commands;
using Windows.Foundation.Collections;
Expand Down Expand Up @@ -35,55 +35,55 @@ internal interface IDscModule
/// <summary>
/// Gets all DSC resource.
/// </summary>
/// <param name="runspace">PowerShell Runspace.</param>
/// <param name="pwsh">PowerShell.</param>
/// <returns>A list with the DSC resource.</returns>
IReadOnlyList<DscResourceInfoInternal> GetAllDscResources(Runspace runspace);
IReadOnlyList<DscResourceInfoInternal> GetAllDscResources(PowerShell pwsh);

/// <summary>
/// Gets all resources in a module.
/// </summary>
/// <param name="runspace">PowerShell Runspace.</param>
/// <param name="pwsh">PowerShell.</param>
/// <param name="moduleSpecification">Module specification.</param>
/// <returns>List of resources of that module and version.</returns>
IReadOnlyList<DscResourceInfoInternal> GetDscResourcesInModule(Runspace runspace, ModuleSpecification moduleSpecification);
IReadOnlyList<DscResourceInfoInternal> GetDscResourcesInModule(PowerShell pwsh, ModuleSpecification moduleSpecification);

/// <summary>
/// Gets a DSC Resource.
/// </summary>
/// <param name="runspace">PowerShell Runspace.</param>
/// <param name="pwsh">PowerShell.</param>
/// <param name="name">Name.</param>
/// <param name="moduleSpecification">Module specification.</param>
/// <returns>DSC Resource from that module and version.</returns>
DscResourceInfoInternal? GetDscResource(Runspace runspace, string name, ModuleSpecification? moduleSpecification);
DscResourceInfoInternal? GetDscResource(PowerShell pwsh, string name, ModuleSpecification? moduleSpecification);

/// <summary>
/// Calls Invoke-DscResource -Method Get from this module.
/// </summary>
/// <param name="runspace">PowerShell Runspace.</param>
/// <param name="pwsh">PowerShell.</param>
/// <param name="settings">Settings.</param>
/// <param name="name">Name.</param>
/// <param name="moduleSpecification">Module specification.</param>
/// <returns>Properties of resource.</returns>
ValueSet InvokeGetResource(Runspace runspace, ValueSet settings, string name, ModuleSpecification? moduleSpecification);
ValueSet InvokeGetResource(PowerShell pwsh, ValueSet settings, string name, ModuleSpecification? moduleSpecification);

/// <summary>
/// Calls Invoke-DscResource -Method Test from this module.
/// </summary>
/// <param name="runspace">PowerShell Runspace.</param>
/// <param name="pwsh">PowerShell.</param>
/// <param name="settings">Settings.</param>
/// <param name="name">Name.</param>
/// <param name="moduleSpecification">Module specification.</param>
/// <returns>Is in desired state.</returns>
bool InvokeTestResource(Runspace runspace, ValueSet settings, string name, ModuleSpecification? moduleSpecification);
bool InvokeTestResource(PowerShell pwsh, ValueSet settings, string name, ModuleSpecification? moduleSpecification);

/// <summary>
/// Calls Invoke-DscResource -Method Set from this module.
/// </summary>
/// <param name="runspace">PowerShell Runspace.</param>
/// <param name="pwsh">PowerShell.</param>
/// <param name="settings">Settings.</param>
/// <param name="name">Name.</param>
/// <param name="moduleSpecification">Module specification.</param>
/// <returns>If a reboot is required.</returns>
bool InvokeSetResource(Runspace runspace, ValueSet settings, string name, ModuleSpecification? moduleSpecification);
bool InvokeSetResource(PowerShell pwsh, ValueSet settings, string name, ModuleSpecification? moduleSpecification);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,10 @@ internal static class ErrorCodes
/// Internal error calling Invoke-DscResource Set.
/// </summary>
internal const int WinGetConfigUnitInvokeSet = unchecked((int)0x8A15C106);

/// <summary>
/// Internal error calling Get-DscResource. More than one module found with the same version.
/// </summary>
internal const int WinGetConfigUnitModuleConflict = unchecked((int)0x8A15C107);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// -----------------------------------------------------------------------------
// <copyright file="GetDscResourceModuleConflict.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
// </copyright>
// -----------------------------------------------------------------------------

namespace Microsoft.Management.Configuration.Processor.Exceptions
{
using System;
using System.Management.Automation;
using Microsoft.PowerShell.Commands;

/// <summary>
/// A call to Get-DscResource failed because at least two modules with the same version where found in the module path.
/// If you are getting this verify the module path.
/// </summary>
internal class GetDscResourceModuleConflict : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="GetDscResourceModuleConflict"/> class.
/// </summary>
/// <param name="resourceName">Resource name.</param>
/// <param name="module">Optional module.</param>
/// <param name="inner">The original runtime exception thrown.</param>
public GetDscResourceModuleConflict(string? resourceName, ModuleSpecification? module, RuntimeException inner)
: base($"Multiple modules with same version in module path: {resourceName?.ToString() ?? "<no resource>"} [{module?.ToString() ?? "<no module>"}]", inner)
{
this.HResult = ErrorCodes.WinGetConfigUnitModuleConflict;
this.ResourceName = resourceName;
this.Module = module;
}

/// <summary>
/// Gets the resource name.
/// </summary>
public string? ResourceName { get; }

/// <summary>
/// Gets the module, if any.
/// </summary>
public ModuleSpecification? Module { get; }
}
}
Loading

0 comments on commit 0d54209

Please sign in to comment.