/// <summary> /// Existing Key = HKCU and HKLM\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell /// Proposed value = Existing default execution policy if not already specified /// /// Schema: /// { /// "shell-ID-string:ExecutionPolicy" : "execution policy string" /// } /// /// TODO: In a single config file, it might be better to nest this. It is unnecessary complexity until a need arises for more nested values. /// </summary> /// <param name="scope">Whether this is a system-wide or per-user setting.</param> /// <param name="shellId">The shell associated with this policy. Typically, it is "Microsoft.PowerShell".</param> /// <returns>The execution policy if found. Null otherwise.</returns> internal string GetExecutionPolicy(ConfigScope scope, string shellId) { string key = GetExecutionPolicySettingKey(shellId); string execPolicy = ReadValueFromFile <string>(scope, key); return(string.IsNullOrEmpty(execPolicy) ? null : execPolicy); }
public ConfigData(ConfigDefinition config, object value, ConfigScope scope, string appliesTo) { Definition = config ?? throw new ArgumentNullException(nameof(config)); Value = value; Scope = scope; AppliesTo = appliesTo; }
internal static void UpdateConfig(PSCmdlet cmdlet, string[] name, ConfigScope scope, bool enable) { IEnumerable <WildcardPattern> namePatterns = SessionStateUtilities.CreateWildcardsFromStrings(name, WildcardOptions.IgnoreCase | WildcardOptions.CultureInvariant); GetExperimentalFeatureCommand getExperimentalFeatureCommand = new GetExperimentalFeatureCommand(); getExperimentalFeatureCommand.Context = cmdlet.Context; bool foundFeature = false; foreach (ExperimentalFeature feature in getExperimentalFeatureCommand.GetAvailableExperimentalFeatures(namePatterns)) { foundFeature = true; if (!cmdlet.ShouldProcess(feature.Name)) { return; } PowerShellConfig.Instance.SetExperimentalFeatures(scope, feature.Name, enable); } if (!foundFeature) { string errMsg = string.Format(CultureInfo.InvariantCulture, ExperimentalFeatureStrings.ExperimentalFeatureNameNotFound, name); cmdlet.WriteError(new ErrorRecord(new ItemNotFoundException(errMsg), "ItemNotFoundException", ErrorCategory.ObjectNotFound, name)); return; } cmdlet.WriteWarning(ExperimentalFeatureStrings.ExperimentalFeaturePending); }
/// <summary> /// Corresponding settings of the original Group Policies /// </summary> internal PowerShellPolicies GetPowerShellPolicies(ConfigScope scope) { string scopeDirectory = (scope == ConfigScope.SystemWide) ? psHomeConfigDirectory : appDataConfigDirectory; string fileName = Path.Combine(scopeDirectory, configFileName); return(ReadValueFromFile <PowerShellPolicies>(fileName, nameof(PowerShellPolicies))); }
public IPropertyBag GetPropertyBag(ConfigScope scope) { foreach (IPropertyBag bag in bags) { if (bag.Scope == scope) return bag; } return null; }
public void GenerateVersionNumbers(ConfigScope scope) { if (scope == ConfigScope.Individually) { throw new NotSupportedException(); } GenerateCommitTimestamps(scope == ConfigScope.Globally); }
private static void setConfigKeyValueUnsafe(ConfigScope scope, string key, string value, string path) { string mode = value == null ? "unset" : ""; string scopeString = scope.ToString().ToLower(); string config = String.Format("config --{0} --{1} {2} {3}", scopeString, mode, key, value ?? ""); ExternalProcess.Start("git", config, true, path); }
public void UseScope(string moduleName) { _ModuleConfig = !string.IsNullOrEmpty(moduleName) && _ModuleConfigScope.TryGetValue(moduleName, out ConfigScope configScope) ? configScope : null; _ModuleBaseline = !string.IsNullOrEmpty(moduleName) && _ModuleBaselineScope.TryGetValue(moduleName, out BaselineScope baselineScope) ? baselineScope : null; _Binding = null; _Configuration = null; _Filter = null; _Culture = null; }
/// <summary> /// TODO: Should this return success, fail, or throw? /// </summary> /// <typeparam name="T">The type of value to write.</typeparam> /// <param name="scope">The ConfigScope of the file to update.</param> /// <param name="key">The string key of the value.</param> /// <param name="value">The value to write.</param> private void WriteValueToFile <T>(ConfigScope scope, string key, T value) { if (ConfigScope.CurrentUser == scope && !Directory.Exists(perUserConfigDirectory)) { Directory.CreateDirectory(perUserConfigDirectory); } UpdateValueInFile <T>(scope, key, value, true); }
/// <summary> /// TODO: Should this return success, fail, or throw? /// </summary> /// <typeparam name="T">The type of value to remove.</typeparam> /// <param name="scope">The ConfigScope of the file to update.</param> /// <param name="key">The string key of the value.</param> private void RemoveValueFromFile <T>(ConfigScope scope, string key) { string fileName = GetConfigFilePath(scope); // Optimization: If the file doesn't exist, there is nothing to remove if (File.Exists(fileName)) { UpdateValueInFile <T>(scope, key, default(T), false); } }
/// <summary> /// Existing Key = HKLM:\System\CurrentControlSet\Control\Session Manager\Environment /// Proposed value = %ProgramFiles%\PowerShell\Modules by default /// Note: There is no setter because this value is immutable. /// </summary> /// <param name="scope">Whether this is a system-wide or per-user setting.</param> /// <returns>Value if found, null otherwise. The behavior matches ModuleIntrinsics.GetExpandedEnvironmentVariable().</returns> internal string GetModulePath(ConfigScope scope) { string modulePath = ReadValueFromFile <string>(scope, Constants.PSModulePathEnvVar); if (!string.IsNullOrEmpty(modulePath)) { modulePath = Environment.ExpandEnvironmentVariables(modulePath); } return(modulePath); }
internal void Add(ConfigScope scope) { if (scope.Type == ScopeType.Module && !string.IsNullOrEmpty(scope.ModuleName)) { _ModuleConfigScope.Add(scope.ModuleName, scope); } else if (scope.Type == ScopeType.Workspace) { _WorkspaceConfig = scope; } }
public static void SetConfigKeyValue(ConfigScope scope, string key, string value, string path = "") { try { setConfigKeyValueUnsafe(scope, key, value, path); } catch (ExternalProcessException) { return; } }
/// <summary> /// Existing Key = HKCU and HKLM\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell /// Proposed value = Existing default execution policy if not already specified /// /// Schema: /// { /// "shell-ID-string:ExecutionPolicy" : "execution policy string" /// } /// /// TODO: In a single config file, it might be better to nest this. It is unnecessary complexity until a need arises for more nested values. /// </summary> /// <param name="scope">Whether this is a system-wide or per-user setting.</param> /// <param name="shellId">The shell associated with this policy. Typically, it is "Microsoft.PowerShell"</param> /// <returns>The execution policy if found. Null otherwise.</returns> internal string GetExecutionPolicy(ConfigScope scope, string shellId) { string execPolicy = null; string valueName = string.Concat(shellId, ":", "ExecutionPolicy"); string rawExecPolicy = ReadValueFromFile <string>(scope, valueName); if (!String.IsNullOrEmpty(rawExecPolicy)) { execPolicy = rawExecPolicy; } return(execPolicy); }
/// <summary> /// Existing Key = HKLM:\System\CurrentControlSet\Control\Session Manager\Environment /// Proposed value = %ProgramFiles%\PowerShell\Modules by default /// Note: There is no setter because this value is immutable. /// </summary> /// <param name="scope">Whether this is a system-wide or per-user setting.</param> /// <returns>Value if found, null otherwise. The behavior matches ModuleIntrinsics.GetExpandedEnvironmentVariable().</returns> internal string GetModulePath(ConfigScope scope) { string scopeDirectory = scope == ConfigScope.SystemWide ? psHomeConfigDirectory : appDataConfigDirectory; string fileName = Path.Combine(scopeDirectory, configFileName); string modulePath = ReadValueFromFile <string>(fileName, Constants.PSModulePathEnvVar); if (!string.IsNullOrEmpty(modulePath)) { modulePath = Environment.ExpandEnvironmentVariables(modulePath); } return(modulePath); }
/// <summary> /// TODO: Should this return success, fail, or throw? /// </summary> /// <typeparam name="T">The type of value to write.</typeparam> /// <param name="scope">The ConfigScope of the file to update.</param> /// <param name="key">The string key of the value.</param> /// <param name="value">The value to write.</param> private void WriteValueToFile <T>(ConfigScope scope, string key, T value) { // Defaults to system wide. if (ConfigScope.CurrentUser == scope) { // Exceptions are not caught so that they will propagate to the // host for display to the user. // CreateDirectory will succeed if the directory already exists // so there is no reason to check Directory.Exists(). Directory.CreateDirectory(perUserConfigDirectory); } UpdateValueInFile <T>(scope, key, value, true); }
/// <inheritdoc/> public IEnumerable <ConfigData> ListConfigs(ConfigFilter filter = null) { IList <ConfigData> results = new List <ConfigData>(); // include all values ISet <string> noNeedForDefault = new HashSet <string>(); foreach (var appliesToSection in _root.GetChildren()) { foreach (var configSection in appliesToSection.GetChildren()) { string key = configSection.Key; if (_configDefinitionMap.TryGetValue(key, out var configDefinition)) { (object value, string providerId) = GetConfigValueOrDefault(configSection, configDefinition); ConfigScope scope = ConfigScopeHelper.GetScopeByProviderId(providerId); results.Add(new ConfigData(configDefinition, value, scope, appliesToSection.Key)); // if a config is already set at global level, there's no need to return its default value if (string.Equals(ConfigFilter.GlobalAppliesTo, appliesToSection.Key, StringComparison.OrdinalIgnoreCase)) { noNeedForDefault.Add(configDefinition.Key); } } } } // include default values IEnumerable <string> keys = filter?.Keys ?? Enumerable.Empty <string>(); bool isRegisteredKey(string key) => _configDefinitionMap.Keys.Contains(key, StringComparer.OrdinalIgnoreCase); IEnumerable <ConfigDefinition> configDefinitions = keys.Any() ? keys.Where(isRegisteredKey).Select(key => _configDefinitionMap[key]) : OrderedConfigDefinitionMap.Select(x => x.Value); configDefinitions.Where(x => !noNeedForDefault.Contains(x.Key)).Select(x => GetDefaultConfigData(x)).ForEach(x => results.Add(x)); if (keys.Any()) { results = results.Where(x => keys.Contains(x.Definition.Key, StringComparer.OrdinalIgnoreCase)).ToList(); } string appliesTo = filter?.AppliesTo; if (!string.IsNullOrEmpty(appliesTo)) { results = results.Where(x => string.Equals(appliesTo, x.AppliesTo, StringComparison.OrdinalIgnoreCase)).ToList(); } return(results); }
public static IEnumerable <string> GetConfigKeyValue(ConfigScope scope, string key, string path = "") { try { string scopeString = scope.ToString().ToLower(); string config = String.Format("config --{0} {1}", scopeString, key); ExternalProcess.Result result = ExternalProcess.Start("git", config, true, path); return(result.StdOut); } catch (ExternalProcessException) { return(Array.Empty <string>()); } }
public static void SetConfigKeyValue(ConfigScope scope, string key, string value, string path = "") { try { setConfigKeyValueUnsafe(scope, key, value, path); } catch (Exception ex) { if (ex is ExternalProcessFailureException || ex is ExternalProcessSystemException) { return; } throw; } }
internal void RemoveExecutionPolicy(ConfigScope scope, string shellId) { string scopeDirectory = psHomeConfigDirectory; // Defaults to system wide. if (ConfigScope.CurrentUser == scope) { scopeDirectory = appDataConfigDirectory; } string fileName = Path.Combine(scopeDirectory, configFileName); string valueName = string.Concat(shellId, ":", "ExecutionPolicy"); RemoveValueFromFile <string>(fileName, valueName); }
internal void SetExecutionPolicy(ConfigScope scope, string shellId, string executionPolicy) { // Defaults to system wide. if (ConfigScope.CurrentUser == scope) { // Exceptions are not caught so that they will propagate to the // host for display to the user. // CreateDirectory will succeed if the directory already exists // so there is no reason to check Directory.Exists(). Directory.CreateDirectory(perUserConfigDirectory); } string valueName = string.Concat(shellId, ":", "ExecutionPolicy"); WriteValueToFile <string>(scope, valueName, executionPolicy); }
/// <summary> /// Read a value from the configuration file. /// </summary> /// <typeparam name="T">The type of the value</typeparam> /// <param name="scope">The ConfigScope of the configuration file to update.</param> /// <param name="key">The string key of the value.</param> /// <param name="defaultValue">The default value to return if the key is not present.</param> private T ReadValueFromFile <T>(ConfigScope scope, string key, T defaultValue = default) { string fileName = GetConfigFilePath(scope); JObject configData = configRoots[(int)scope]; if (configData == null) { if (File.Exists(fileName)) { try { // Open file for reading, but allow multiple readers fileLock.EnterReadLock(); using var stream = OpenFileStreamWithRetry(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); using var jsonReader = new JsonTextReader(new StreamReader(stream)); configData = serializer.Deserialize <JObject>(jsonReader) ?? emptyConfig; } catch (Exception exc) { throw PSTraceSource.NewInvalidOperationException(exc, PSConfigurationStrings.CanNotConfigurationFile, args: fileName); } finally { fileLock.ExitReadLock(); } } else { configData = emptyConfig; } // Set the configuration cache. JObject originalValue = Interlocked.CompareExchange(ref configRoots[(int)scope], configData, null); if (originalValue != null) { configData = originalValue; } } if (configData != emptyConfig && configData.TryGetValue(key, StringComparison.OrdinalIgnoreCase, out JToken jToken)) { return(jToken.ToObject <T>(serializer) ?? defaultValue); } return(defaultValue); }
/// <summary> /// Set the enabled list of experimental features in the config file. /// </summary> /// <param name="scope">The ConfigScope of the configuration file to update.</param> /// <param name="featureName">The name of the experimental feature to change in the configuration.</param> /// <param name="setEnabled">If true, add to configuration; otherwise, remove from configuration.</param> internal void SetExperimentalFeatures(ConfigScope scope, string featureName, bool setEnabled) { var features = new List <string>(GetExperimentalFeatures()); bool containsFeature = features.Contains(featureName); if (setEnabled && !containsFeature) { features.Add(featureName); WriteValueToFile <string[]>(scope, "ExperimentalFeatures", features.ToArray()); } else if (!setEnabled && containsFeature) { features.Remove(featureName); WriteValueToFile <string[]>(scope, "ExperimentalFeatures", features.ToArray()); } }
public static string GetProviderIdByScope(ConfigScope scope) { switch (scope) { case ConfigScope.CurrentUser: return(Constants.ConfigProviderIds.UserConfig); case ConfigScope.Environment: return(Constants.ConfigProviderIds.EnvironmentVariable); case ConfigScope.Process: return(Constants.ConfigProviderIds.ProcessConfig); case ConfigScope.Default: default: return(Constants.ConfigProviderIds.None); } }
/// <summary> /// Existing Key = HKCU and HKLM\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell /// Proposed value = Existing default execution policy if not already specified /// /// Schema: /// { /// "shell-ID-string:ExecutionPolicy" : "execution policy string" /// } /// /// TODO: In a single config file, it might be better to nest this. It is unnecessary complexity until a need arises for more nested values. /// </summary> /// <param name="scope">Whether this is a system-wide or per-user setting.</param> /// <param name="shellId">The shell associated with this policy. Typically, it is "Microsoft.PowerShell"</param> /// <returns>The execution policy if found. Null otherwise.</returns> internal string GetExecutionPolicy(ConfigScope scope, string shellId) { string execPolicy = null; string scopeDirectory = psHomeConfigDirectory; // Defaults to system wide. if (ConfigScope.CurrentUser == scope) { scopeDirectory = appDataConfigDirectory; } string fileName = Path.Combine(scopeDirectory, configFileName); string valueName = string.Concat(shellId, ":", "ExecutionPolicy"); string rawExecPolicy = ReadValueFromFile <string>(fileName, valueName); if (!String.IsNullOrEmpty(rawExecPolicy)) { execPolicy = rawExecPolicy; } return(execPolicy); }
/// <summary> /// Read a value from the configuration file. /// </summary> /// <typeparam name="T">The type of the value</typeparam> /// <param name="scope">The ConfigScope of the configuration file to update.</param> /// <param name="key">The string key of the value.</param> /// <param name="defaultValue">The default value to return if the key is not present.</param> /// <param name="readImpl"></param> private T ReadValueFromFile <T>(ConfigScope scope, string key, T defaultValue = default(T), Func <JToken, JsonSerializer, T, T> readImpl = null) { string fileName = GetConfigFilePath(scope); if (!File.Exists(fileName)) { return(defaultValue); } // Open file for reading, but allow multiple readers fileLock.EnterReadLock(); try { // The config file can be locked by another process // so we wait some milliseconds in 'WaitForFile()' for recovery before stop current process. using (var readerStream = WaitForFile(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var streamReader = new StreamReader(readerStream)) using (var jsonReader = new JsonTextReader(streamReader)) { var settings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.None, MaxDepth = 10 }; var serializer = JsonSerializer.Create(settings); var configData = serializer.Deserialize <JObject>(jsonReader); if (configData != null && configData.TryGetValue(key, StringComparison.OrdinalIgnoreCase, out JToken jToken)) { return(readImpl != null?readImpl(jToken, serializer, defaultValue) : jToken.ToObject <T>(serializer)); } } } finally { fileLock.ExitReadLock(); } return(defaultValue); }
/// <summary> /// Read a value from the configuration file. /// </summary> /// <typeparam name="T">The type of the value</typeparam> /// <param name="scope">The ConfigScope of the configuration file to update.</param> /// <param name="key">The string key of the value.</param> /// <param name="defaultValue">The default value to return if the key is not present.</param> /// <param name="readImpl"></param> private T ReadValueFromFile <T>(ConfigScope scope, string key, T defaultValue = default(T), Func <JToken, JsonSerializer, T, T> readImpl = null) { string fileName = GetConfigFilePath(scope); if (!File.Exists(fileName)) { return(defaultValue); } // Open file for reading, but allow multiple readers fileLock.EnterReadLock(); try { using (var streamReader = new StreamReader(fileName)) using (var jsonReader = new JsonTextReader(streamReader)) { var settings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.None, MaxDepth = 10 }; var serializer = JsonSerializer.Create(settings); var configData = serializer.Deserialize <JObject>(jsonReader); if (configData != null && configData.TryGetValue(key, StringComparison.OrdinalIgnoreCase, out JToken jToken)) { return(readImpl != null?readImpl(jToken, serializer, defaultValue) : jToken.ToObject <T>(serializer)); } } } finally { fileLock.ExitReadLock(); } return(defaultValue); }
/// <summary> /// Update a value in the configuration file. /// </summary> /// <typeparam name="T">The type of the value</typeparam> /// <param name="scope">The ConfigScope of the configuration file to update.</param> /// <param name="key">The string key of the value.</param> /// <param name="value">The value to set.</param> /// <param name="addValue">Whether the key-value pair should be added to or removed from the file.</param> private void UpdateValueInFile <T>(ConfigScope scope, string key, T value, bool addValue) { try { string fileName = GetConfigFilePath(scope); fileLock.EnterWriteLock(); // Since multiple properties can be in a single file, replacement is required instead of overwrite if a file already exists. // Handling the read and write operations within a single FileStream prevents other processes from reading or writing the file while // the update is in progress. It also locks out readers during write operations. JObject jsonObject = null; using FileStream fs = OpenFileStreamWithRetry(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); // UTF8, BOM detection, and bufferSize are the same as the basic stream constructor. // The most important parameter here is the last one, which keeps underlying stream open after StreamReader is disposed // so that it can be reused for the subsequent write operation. using (StreamReader streamRdr = new StreamReader(fs, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) using (JsonTextReader jsonReader = new JsonTextReader(streamRdr)) { // Safely determines whether there is content to read from the file bool isReadSuccess = jsonReader.Read(); if (isReadSuccess) { // Read the stream into a root JObject for manipulation jsonObject = serializer.Deserialize <JObject>(jsonReader); JProperty propertyToModify = jsonObject.Property(key); if (propertyToModify == null) { // The property doesn't exist, so add it if (addValue) { jsonObject.Add(new JProperty(key, value)); } // else the property doesn't exist so there is nothing to remove } else { // The property exists if (addValue) { propertyToModify.Replace(new JProperty(key, value)); } else { propertyToModify.Remove(); } } } else { // The file doesn't already exist and we want to write to it or it exists with no content. // A new file will be created that contains only this value. // If the file doesn't exist and a we don't want to write to it, no action is needed. if (addValue) { jsonObject = new JObject(new JProperty(key, value)); } else { return; } } } // Reset the stream position to the beginning so that the // changes to the file can be written to disk fs.Seek(0, SeekOrigin.Begin); // Update the file with new content using (StreamWriter streamWriter = new StreamWriter(fs)) using (JsonTextWriter jsonWriter = new JsonTextWriter(streamWriter)) { // The entire document exists within the root JObject. // I just need to write that object to produce the document. jsonObject.WriteTo(jsonWriter); // This trims the file if the file shrank. If the file grew, // it is a no-op. The purpose is to trim extraneous characters // from the file stream when the resultant JObject is smaller // than the input JObject. fs.SetLength(fs.Position); } // Refresh the configuration cache. Interlocked.Exchange(ref configRoots[(int)scope], jsonObject); } finally { fileLock.ExitWriteLock(); } }
/// <summary> /// Corresponding settings of the original Group Policies. /// </summary> internal PowerShellPolicies GetPowerShellPolicies(ConfigScope scope) { return(ReadValueFromFile <PowerShellPolicies>(scope, nameof(PowerShellPolicies))); }
internal void SetExecutionPolicy(ConfigScope scope, string shellId, string executionPolicy) { string key = GetExecutionPolicySettingKey(shellId); WriteValueToFile <string>(scope, key, executionPolicy); }
internal void RemoveExecutionPolicy(ConfigScope scope, string shellId) { string key = GetExecutionPolicySettingKey(shellId); RemoveValueFromFile <string>(scope, key); }