winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

PowerShellConfigurationSetProcessorFactory.cs (12189B)


      1 // -----------------------------------------------------------------------------
      2 // <copyright file="PowerShellConfigurationSetProcessorFactory.cs" company="Microsoft Corporation">
      3 //     Copyright (c) Microsoft Corporation. Licensed under the MIT License.
      4 // </copyright>
      5 // -----------------------------------------------------------------------------
      6 
      7 namespace Microsoft.Management.Configuration.Processor
      8 {
      9     using System;
     10     using System.Collections.Generic;
     11     using System.IO;
     12     using System.Text;
     13     using Microsoft.Management.Configuration;
     14     using Microsoft.Management.Configuration.Processor.Factory;
     15     using Microsoft.Management.Configuration.Processor.PowerShell.ProcessorEnvironments;
     16     using Microsoft.Management.Configuration.Processor.PowerShell.Set;
     17     using Microsoft.Management.Configuration.SetProcessorFactory;
     18     using static Microsoft.Management.Configuration.Processor.PowerShell.Constants.PowerShellConstants;
     19 
     20     /// <summary>
     21     /// IConfigurationSetProcessorFactory implementation using PowerShell DSC v2.
     22     /// </summary>
     23 #if WinGetCsWinRTEmbedded
     24     internal
     25 #else
     26     public
     27 #endif
     28         sealed partial class PowerShellConfigurationSetProcessorFactory : ConfigurationSetProcessorFactoryBase, IConfigurationSetProcessorFactory, IPowerShellConfigurationProcessorFactoryProperties, IPwshConfigurationSetProcessorFactoryProperties
     29     {
     30         // Backing variables for properties that are restricted in limit mode.
     31         private PowerShellConfigurationProcessorType processorType = PowerShellConfigurationProcessorType.Default;
     32         private IReadOnlyList<string>? additionalModulePaths;
     33         private IReadOnlyList<string>? implicitModulePaths;
     34         private PowerShellConfigurationProcessorPolicy policy = PowerShellConfigurationProcessorPolicy.Default;
     35         private PowerShellConfigurationProcessorLocation location = PowerShellConfigurationProcessorLocation.Default;
     36         private string? customLocation;
     37 
     38         /// <summary>
     39         /// Initializes a new instance of the <see cref="PowerShellConfigurationSetProcessorFactory"/> class.
     40         /// </summary>
     41         public PowerShellConfigurationSetProcessorFactory()
     42         {
     43         }
     44 
     45         /// <summary>
     46         /// Gets or sets the processor type.
     47         /// </summary>
     48         public PowerShellConfigurationProcessorType ProcessorType
     49         {
     50             get
     51             {
     52                 return this.processorType;
     53             }
     54 
     55             set
     56             {
     57                 if (this.IsLimitMode())
     58                 {
     59                     throw new InvalidOperationException("Setting ProcessorType in limit mode is invalid.");
     60                 }
     61 
     62                 this.processorType = value;
     63             }
     64         }
     65 
     66         /// <summary>
     67         /// Gets or sets the additional module paths.
     68         /// </summary>
     69         public IReadOnlyList<string>? AdditionalModulePaths
     70         {
     71             get
     72             {
     73                 return this.additionalModulePaths;
     74             }
     75 
     76             set
     77             {
     78                 if (this.IsLimitMode())
     79                 {
     80                     throw new InvalidOperationException("Setting AdditionalModulePaths in limit mode is invalid.");
     81                 }
     82 
     83                 // Create a copy of incoming value
     84                 List<string> newModulePaths = new List<string>();
     85                 if (value != null)
     86                 {
     87                     foreach (string path in value)
     88                     {
     89                         newModulePaths.Add(path);
     90                     }
     91                 }
     92 
     93                 // Add implicit module paths if applicable
     94                 if (this.implicitModulePaths != null)
     95                 {
     96                     foreach (string path in this.implicitModulePaths)
     97                     {
     98                         if (!newModulePaths.Contains(path))
     99                         {
    100                             newModulePaths.Add(path);
    101                         }
    102                     }
    103                 }
    104 
    105                 this.additionalModulePaths = newModulePaths;
    106             }
    107         }
    108 
    109         /// <summary>
    110         /// Gets or sets the implicit module paths. These paths are always included in AdditionalModulePaths.
    111         /// </summary>
    112         public IReadOnlyList<string>? ImplicitModulePaths
    113         {
    114             get
    115             {
    116                 return this.implicitModulePaths;
    117             }
    118 
    119             set
    120             {
    121                 if (this.IsLimitMode())
    122                 {
    123                     throw new InvalidOperationException("Setting ImplicitModulePaths in limit mode is invalid.");
    124                 }
    125 
    126                 this.implicitModulePaths = value;
    127 
    128                 // Apply to additional module paths if applicable.
    129                 if (this.implicitModulePaths != null)
    130                 {
    131                     List<string> newModulePaths = new List<string>();
    132                     if (this.additionalModulePaths != null)
    133                     {
    134                         foreach (string path in this.additionalModulePaths)
    135                         {
    136                             newModulePaths.Add(path);
    137                         }
    138                     }
    139 
    140                     foreach (string path in this.implicitModulePaths)
    141                     {
    142                         if (!newModulePaths.Contains(path))
    143                         {
    144                             newModulePaths.Add(path);
    145                         }
    146                     }
    147 
    148                     this.additionalModulePaths = newModulePaths;
    149                 }
    150             }
    151         }
    152 
    153         /// <summary>
    154         /// Gets or sets the configuration policy.
    155         /// </summary>
    156         public PowerShellConfigurationProcessorPolicy Policy
    157         {
    158             get
    159             {
    160                 return this.policy;
    161             }
    162 
    163             set
    164             {
    165                 if (this.IsLimitMode())
    166                 {
    167                     throw new InvalidOperationException("Setting Policy in limit mode is invalid.");
    168                 }
    169 
    170                 this.policy = value;
    171             }
    172         }
    173 
    174         /// <summary>
    175         /// Gets or sets the configuration policy.
    176         /// </summary>
    177         PwshConfigurationProcessorPolicy IPwshConfigurationSetProcessorFactoryProperties.Policy
    178         {
    179             get { return Helpers.TypeHelpers.ToPwshConfigurationProcessorPolicy(this.Policy); }
    180             set { this.Policy = Helpers.TypeHelpers.ToPowerShellConfigurationProcessorPolicy(value); }
    181         }
    182 
    183         /// <summary>
    184         /// Gets or sets the module location.
    185         /// </summary>
    186         public PowerShellConfigurationProcessorLocation Location
    187         {
    188             get
    189             {
    190                 return this.location;
    191             }
    192 
    193             set
    194             {
    195                 if (this.IsLimitMode())
    196                 {
    197                     throw new InvalidOperationException("Setting Location in limit mode is invalid.");
    198                 }
    199 
    200                 this.location = value;
    201             }
    202         }
    203 
    204         /// <summary>
    205         /// Gets or sets the module location.
    206         /// </summary>
    207         PwshConfigurationProcessorLocation IPwshConfigurationSetProcessorFactoryProperties.Location
    208         {
    209             get { return Helpers.TypeHelpers.ToPwshConfigurationProcessorLocation(this.Location); }
    210             set { this.Location = Helpers.TypeHelpers.ToPowerShellConfigurationProcessorLocation(value); }
    211         }
    212 
    213         /// <summary>
    214         /// Gets or sets the install module path. Only used for Scope = Custom.
    215         /// </summary>
    216         public string? CustomLocation
    217         {
    218             get
    219             {
    220                 return this.customLocation;
    221             }
    222 
    223             set
    224             {
    225                 if (this.IsLimitMode())
    226                 {
    227                     throw new InvalidOperationException("Setting CustomLocation in limit mode is invalid.");
    228                 }
    229 
    230                 this.customLocation = value;
    231             }
    232         }
    233 
    234         /// <summary>
    235         /// Gets the winget module path.
    236         /// </summary>
    237         /// <returns>The winget module path.</returns>
    238         internal static string GetWinGetModulePath()
    239         {
    240             return Path.Combine(
    241                     Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
    242                     @"Microsoft\WinGet\Configuration\Modules");
    243         }
    244 
    245         /// <summary>
    246         /// Sends diagnostic if appropriate for PowerShell streams.
    247         /// </summary>
    248         /// <param name="level">The level of this diagnostic message.</param>
    249         /// <param name="pwsh">The PowerShell object.</param>
    250         internal void OnDiagnostics(DiagnosticLevel level, System.Management.Automation.PowerShell pwsh)
    251         {
    252             if (this.AreDiagnosticsEnabled() && level >= this.MinimumLevel && pwsh.HadErrors)
    253             {
    254                 var builder = new StringBuilder();
    255 
    256                 // There are the last commands ran by that PowerShell obj, not all in our session.
    257                 builder.Append("PowerShellCommands: ");
    258                 foreach (var c in pwsh.Commands.Commands)
    259                 {
    260                     builder.Append($"['{c.CommandText}'");
    261                     if (c.Parameters.Count > 0)
    262                     {
    263                         builder.Append(" Parameters: ");
    264                         foreach (var p in c.Parameters)
    265                         {
    266                             builder.Append($"{p.Name} = '{p.Value}' ");
    267                         }
    268 
    269                         builder.Append("]");
    270                     }
    271 
    272                     builder.AppendLine();
    273                 }
    274 
    275                 foreach (var error in pwsh.Streams.Error)
    276                 {
    277                     builder.AppendLine($"[WriteError] {error}");
    278                 }
    279 
    280                 this.OnDiagnostics(level, builder.ToString());
    281             }
    282         }
    283 
    284         /// <inheritdoc />
    285         protected override IConfigurationSetProcessor CreateSetProcessorInternal(ConfigurationSet? set, bool isLimitMode)
    286         {
    287             var envFactory = new ProcessorEnvironmentFactory(this.ProcessorType);
    288             var processorEnvironment = envFactory.CreateEnvironment(
    289                 this,
    290                 this.Policy);
    291 
    292             if (this.AdditionalModulePaths is not null)
    293             {
    294                 processorEnvironment.PrependPSModulePaths(this.AdditionalModulePaths);
    295             }
    296 
    297             // Always add the winget path.
    298             var wingetModulePath = GetWinGetModulePath();
    299             processorEnvironment.PrependPSModulePath(wingetModulePath);
    300             if (this.Location == PowerShellConfigurationProcessorLocation.WinGetModulePath)
    301             {
    302                 this.OnDiagnostics(DiagnosticLevel.Verbose, "Using winget module path");
    303                 processorEnvironment.SetLocation(PowerShellConfigurationProcessorLocation.Custom, wingetModulePath);
    304             }
    305             else if (this.Location == PowerShellConfigurationProcessorLocation.Custom)
    306             {
    307                 if (string.IsNullOrEmpty(this.CustomLocation))
    308                 {
    309                     throw new ArgumentNullException(nameof(this.CustomLocation));
    310                 }
    311 
    312                 processorEnvironment.SetLocation(this.Location, this.CustomLocation);
    313                 processorEnvironment.PrependPSModulePath(this.CustomLocation);
    314             }
    315             else
    316             {
    317                 processorEnvironment.SetLocation(this.Location, null);
    318             }
    319 
    320             this.OnDiagnostics(DiagnosticLevel.Verbose, $"  Effective module path:\n{processorEnvironment.GetVariable<string>(Variables.PSModulePath)}");
    321 
    322             processorEnvironment.ValidateRunspace();
    323 
    324             return new PowerShellConfigurationSetProcessor(processorEnvironment, set, isLimitMode) { SetProcessorFactory = this };
    325         }
    326     }
    327 }