MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections;6using System.Collections.Generic;7using System.Collections.ObjectModel;8using System.Management.Automation;9using System.Management.Automation.Provider;10 11using Dbg = System.Management.Automation;12 13namespace Microsoft.PowerShell.Commands14{15 /// <summary>16 /// This provider is the data accessor for environment variables. It uses17 /// the SessionStateProviderBase as the base class to produce a view on18 /// session state data.19 /// </summary>20 [CmdletProvider(EnvironmentProvider.ProviderName, ProviderCapabilities.ShouldProcess)]21 public sealed class EnvironmentProvider : SessionStateProviderBase22 {23 /// <summary>24 /// Gets the name of the provider.25 /// </summary>26 public const string ProviderName = "Environment";27 28 #region Constructor29 30 /// <summary>31 /// The constructor for the provider that exposes environment variables to the user32 /// as drives.33 /// </summary>34 public EnvironmentProvider()35 {36 }37 38 #endregion Constructor39 40 #region DriveCmdletProvider overrides41 42 /// <summary>43 /// Initializes the alias drive.44 /// </summary>45 /// <returns>46 /// An array of a single PSDriveInfo object representing the alias drive.47 /// </returns>48 protected override Collection<PSDriveInfo> InitializeDefaultDrives()49 {50 string description = SessionStateStrings.EnvironmentDriveDescription;51 52 PSDriveInfo envDrive =53 new PSDriveInfo(54 DriveNames.EnvironmentDrive,55 ProviderInfo,56 string.Empty,57 description,58 null);59 60 Collection<PSDriveInfo> drives = new Collection<PSDriveInfo>();61 drives.Add(envDrive);62 return drives;63 }64 65 #endregion DriveCmdletProvider overrides66 67 #region protected members68 69 /// <summary>70 /// Gets a environment variable from session state.71 /// </summary>72 /// <param name="name">73 /// The name of the environment variable to retrieve.74 /// </param>75 /// <returns>76 /// A DictionaryEntry that represents the value of the environment variable.77 /// </returns>78 internal override object GetSessionStateItem(string name)79 {80 Dbg.Diagnostics.Assert(81 !string.IsNullOrEmpty(name),82 "The caller should verify this parameter");83 84 object result = null;85 86 string value = Environment.GetEnvironmentVariable(name);87 88 if (value != null)89 {90 result = new DictionaryEntry(name, value);91 }92 93 return result;94 }95 96 /// <summary>97 /// Sets the environment variable of the specified name to the specified value.98 /// </summary>99 /// <param name="name">100 /// The name of the environment variable to set.101 /// </param>102 /// <param name="value">103 /// The new value for the environment variable.104 /// </param>105 /// <param name="writeItem">106 /// If true, the item that was set should be written to WriteItemObject.107 /// </param>108 internal override void SetSessionStateItem(string name, object value, bool writeItem)109 {110 Dbg.Diagnostics.Assert(111 !string.IsNullOrEmpty(name),112 "The caller should verify this parameter");113 114 if (value == null)115 {116 Environment.SetEnvironmentVariable(name, null);117 }118 else119 {120 // First see if we got a DictionaryEntry which represents121 // an item for this provider. If so, use the value from122 // the dictionary entry.123 124 if (value is DictionaryEntry)125 {126 value = ((DictionaryEntry)value).Value;127 }128 129 string stringValue = value as string;130 if (stringValue == null)131 {132 // try using ETS to convert to a string.133 134 PSObject wrappedObject = PSObject.AsPSObject(value);135 stringValue = wrappedObject.ToString();136 }137 138 Environment.SetEnvironmentVariable(name, stringValue);139 140 DictionaryEntry item = new DictionaryEntry(name, stringValue);141 142 if (writeItem)143 {144 WriteItemObject(item, name, false);145 }146 }147 }148 149 /// <summary>150 /// Removes the specified environment variable from session state.151 /// </summary>152 /// <param name="name">153 /// The name of the environment variable to remove from session state.154 /// </param>155 internal override void RemoveSessionStateItem(string name)156 {157 Dbg.Diagnostics.Assert(158 !string.IsNullOrEmpty(name),159 "The caller should verify this parameter");160 161 Environment.SetEnvironmentVariable(name, null);162 }163 164 /// <summary>165 /// Gets a flattened view of the environment variables in session state.166 /// </summary>167 /// <returns>168 /// An IDictionary representing the flattened view of the environment variables in169 /// session state.170 /// </returns>171 internal override IDictionary GetSessionStateTable()172 {173 // Environment variables are case-sensitive on Unix and174 // case-insensitive on Windows175#if UNIX176 Dictionary<string, DictionaryEntry> providerTable =177 new Dictionary<string, DictionaryEntry>(StringComparer.Ordinal);178#else179 Dictionary<string, DictionaryEntry> providerTable =180 new Dictionary<string, DictionaryEntry>(StringComparer.OrdinalIgnoreCase);181#endif182 183 // The environment variables returns a dictionary of keys and values that are184 // both strings. We want to return a dictionary with the key as a string and185 // the value as the DictionaryEntry containing both the name and env variable186 // value.187 188 IDictionary environmentTable = Environment.GetEnvironmentVariables();189 foreach (DictionaryEntry entry in environmentTable)190 {191 if (!providerTable.TryAdd((string)entry.Key, entry))192 { // Windows only: duplicate key (variable name that differs only in case)193 // NOTE: Even though this shouldn't happen, it can, e.g. when npm194 // creates duplicate environment variables that differ only in case -195 // see https://github.com/PowerShell/PowerShell/issues/6305.196 // However, because retrieval *by name* later is invariably197 // case-INsensitive, in effect only a *single* variable exists.198 // We simply ask Environment.GetEnvironmentVariable() for the effective value199 // and use that as the only entry, because for a given key 'foo' (and all its case variations),200 // that is guaranteed to match what $env:FOO and [environment]::GetEnvironmentVariable('foo') return.201 // (If, by contrast, we just used `entry` as-is every time a duplicate is encountered,202 // it could - intermittently - represent a value *other* than the effective one.)203 string effectiveValue = Environment.GetEnvironmentVariable((string)entry.Key);204 if (((string)entry.Value).Equals(effectiveValue, StringComparison.Ordinal))205 { // We've found the effective definition.206 // Note: We *recreate* the entry so that the specific name casing of the207 // effective definition is also reflected. However, if the case variants208 // define the same value, it is unspecified which name variant is reflected209 // in Get-Item env: output; given the always case-insensitive nature of the retrieval,210 // that shouldn't matter.211 providerTable.Remove((string)entry.Key);212 providerTable.Add((string)entry.Key, entry);213 }214 }215 }216 217 return providerTable;218 }219 220 /// <summary>221 /// Gets the Value property of the DictionaryEntry item.222 /// </summary>223 /// <param name="item">224 /// The item to get the value from.225 /// </param>226 /// <returns>227 /// The value of the item.228 /// </returns>229 internal override object GetValueOfItem(object item)230 {231 Dbg.Diagnostics.Assert(232 item != null,233 "Caller should verify the item parameter");234 235 object value = item;236 237 if (item is DictionaryEntry)238 {239 value = ((DictionaryEntry)item).Value;240 }241 242 return value;243 }244 245 #endregion protected members246 }247}248 