winget-cli

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

Utilities.cs (8220B)


      1 // -----------------------------------------------------------------------------
      2 // <copyright file="Utilities.cs" company="Microsoft Corporation">
      3 //     Copyright (c) Microsoft Corporation. Licensed under the MIT License.
      4 // </copyright>
      5 // -----------------------------------------------------------------------------
      6 
      7 namespace Microsoft.WinGet.Client.Engine.Common
      8 {
      9     using System;
     10     using System.Collections;
     11     using System.Collections.Generic;
     12     using System.IO;
     13     using System.Management.Automation;
     14     using System.Security.Principal;
     15     using System.Threading;
     16     using Microsoft.WinGet.Resources;
     17     using Newtonsoft.Json;
     18     using Newtonsoft.Json.Linq;
     19 
     20     /// <summary>
     21     /// This class contains various helper methods for this project.
     22     /// </summary>
     23     internal static class Utilities
     24     {
     25         /// <summary>
     26         /// Gets a value indicating whether the current assembly is executing in an administrative context.
     27         /// </summary>
     28         [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "Windows only API")]
     29         public static bool ExecutingAsAdministrator
     30         {
     31             get
     32             {
     33                 WindowsIdentity identity = WindowsIdentity.GetCurrent();
     34                 WindowsPrincipal principal = new (identity);
     35                 return principal.IsInRole(WindowsBuiltInRole.Administrator);
     36             }
     37         }
     38 
     39         /// <summary>
     40         /// Gets a value indicating whether the current assembly is executing as a SYSTEM user.
     41         /// </summary>
     42         [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "Windows only API")]
     43         public static bool ExecutingAsSystem
     44         {
     45             get
     46             {
     47                 return WindowsIdentity.GetCurrent().IsSystem;
     48             }
     49         }
     50 
     51         /// <summary>
     52         /// Gets a value indicating whether the current execution context will use in-proc winget.
     53         /// </summary>
     54         public static bool UsesInProcWinget
     55         {
     56             get
     57             {
     58                 return ExecutingAsSystem;
     59             }
     60         }
     61 
     62         /// <summary>
     63         /// Gets a value indicating whether the current thread is executing as STA.
     64         /// </summary>
     65         [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "Windows only API")]
     66         public static bool ThreadIsSTA
     67         {
     68             get
     69             {
     70                 return Thread.CurrentThread.GetApartmentState() == ApartmentState.STA;
     71             }
     72         }
     73 
     74         /// <summary>
     75         /// Gets the windows app path for local app data.
     76         /// </summary>
     77         public static string LocalDataWindowsAppPath
     78         {
     79             get
     80             {
     81                 return Environment.ExpandEnvironmentVariables(@"%LOCALAPPDATA%\Microsoft\WindowsApps");
     82             }
     83         }
     84 
     85         /// <summary>
     86         /// Gets the windows app path for program files.
     87         /// </summary>
     88         public static string ProgramFilesWindowsAppPath
     89         {
     90             get
     91             {
     92                 return Environment.ExpandEnvironmentVariables(@"%PROGRAMFILES%\WindowsApps");
     93             }
     94         }
     95 
     96         /// <summary>
     97         /// Throws if not running as admin.
     98         /// </summary>
     99         public static void VerifyAdmin()
    100         {
    101             if (!Utilities.ExecutingAsAdministrator)
    102             {
    103                 throw new PSNotSupportedException(Resources.RequiresAdminMessage);
    104             }
    105         }
    106 
    107         /// <summary>
    108         /// Adds the WindowsApp local app data path to the user environment path.
    109         /// </summary>
    110         public static void AddWindowsAppToPath()
    111         {
    112             var scope = EnvironmentVariableTarget.User;
    113             string? envPathValue = Environment.GetEnvironmentVariable(Constants.PathEnvVar, scope);
    114             if (string.IsNullOrEmpty(envPathValue) || !envPathValue.Contains(Utilities.LocalDataWindowsAppPath))
    115             {
    116                 Environment.SetEnvironmentVariable(
    117                     Constants.PathEnvVar,
    118                     $"{envPathValue};{Utilities.LocalDataWindowsAppPath}",
    119                     scope);
    120             }
    121         }
    122 
    123         /// <summary>
    124         /// This is based of https://github.com/PowerShell/PowerShell/blob/master/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/JsonObject.cs.
    125         /// So we can convert JSON to Hashtable for Windows PowerShell and PowerShell Core.
    126         /// </summary>
    127         /// <param name="content">String content.</param>
    128         /// <returns>The hashtable.</returns>
    129         public static Hashtable ConvertToHashtable(string content)
    130         {
    131             if (string.IsNullOrEmpty(content))
    132             {
    133                 return new Hashtable();
    134             }
    135 
    136             var obj = JsonConvert.DeserializeObject(
    137                 content,
    138                 new JsonSerializerSettings
    139                 {
    140                     // This TypeNameHandling setting is required to be secure.
    141                     TypeNameHandling = TypeNameHandling.None,
    142                     MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
    143                     MaxDepth = 1024,
    144                 });
    145 
    146             // It only makes sense that the deserialized object is a dictionary to start.
    147             return obj switch
    148             {
    149                 JObject dictionary => PopulateHashTableFromJDictionary(dictionary),
    150                 _ => throw new InvalidDataException()
    151             };
    152         }
    153 
    154         private static Hashtable PopulateHashTableFromJDictionary(JObject entries)
    155         {
    156             Hashtable result = new (entries.Count);
    157             foreach (var entry in entries)
    158             {
    159                 switch (entry.Value)
    160                 {
    161                     case JArray list:
    162                         {
    163                             // Array
    164                             var listResult = PopulateHashTableFromJArray(list);
    165                             result.Add(entry.Key, listResult);
    166                             break;
    167                         }
    168 
    169                     case JObject dic:
    170                         {
    171                             // Dictionary
    172                             var dicResult = PopulateHashTableFromJDictionary(dic);
    173                             result.Add(entry.Key, dicResult);
    174                             break;
    175                         }
    176 
    177                     case JValue value:
    178                         {
    179                             result.Add(entry.Key, value.Value);
    180                             break;
    181                         }
    182                 }
    183             }
    184 
    185             return result;
    186         }
    187 
    188         private static ICollection<object?> PopulateHashTableFromJArray(JArray list)
    189         {
    190             var result = new object?[list.Count];
    191 
    192             for (var index = 0; index < list.Count; index++)
    193             {
    194                 var element = list[index];
    195 
    196                 switch (element)
    197                 {
    198                     case JArray array:
    199                         {
    200                             // Array
    201                             var listResult = PopulateHashTableFromJArray(array);
    202                             result[index] = listResult;
    203                             break;
    204                         }
    205 
    206                     case JObject dic:
    207                         {
    208                             // Dictionary
    209                             var dicResult = PopulateHashTableFromJDictionary(dic);
    210                             result[index] = dicResult;
    211                             break;
    212                         }
    213 
    214                     case JValue value:
    215                         {
    216                             result[index] = value.Value;
    217                             break;
    218                         }
    219                 }
    220             }
    221 
    222             return result;
    223         }
    224     }
    225 }