diff --git a/LICENSE.txt b/LICENSE.txt
index b4baf872a8b2..07e000052329 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -273,5 +273,33 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-----------------------------------------------------------------------------
+***************
+
+The software includes Microsoft.Extensions.Configuration. The MIT License set out below is provided for informational purposes only. It is not the license that governs any part of the software.
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
-------------END OF THIRD PARTY NOTICE----------------------------------------
diff --git a/src/Accounts/Accounts.Test/Mocks/MockDataStore.cs b/src/Accounts/Accounts.Test/Mocks/MockDataStore.cs
index 5f03997356c5..cfed5e22eb64 100644
--- a/src/Accounts/Accounts.Test/Mocks/MockDataStore.cs
+++ b/src/Accounts/Accounts.Test/Mocks/MockDataStore.cs
@@ -382,7 +382,8 @@ public Stream OpenForExclusiveWrite(string path)
() =>
{
writeLocks[path] = false;
- virtualStore[path] = Encoding.UTF8.GetString(buffer);
+ // trim \0 otherwise json fails to parse
+ virtualStore[path] = Encoding.UTF8.GetString(buffer).TrimEnd('\0');
}
);
}
diff --git a/src/Accounts/Accounts/Accounts.format.ps1xml b/src/Accounts/Accounts/Accounts.format.ps1xml
index 818c9fc643a1..e7c23dc3e11c 100644
--- a/src/Accounts/Accounts/Accounts.format.ps1xml
+++ b/src/Accounts/Accounts/Accounts.format.ps1xml
@@ -276,6 +276,61 @@
-
+
+ Microsoft.Azure.Commands.Profile.Models.PSConfig
+
+ Microsoft.Azure.Commands.Profile.Models.PSConfig
+
+
+
+
+ Left
+
+
+
+ Left
+
+
+
+ Left
+
+
+
+ Left
+
+
+
+ Left
+
+
+
+
+
+
+
+ Left
+ Key
+
+
+ Left
+ Value
+
+
+ Left
+ AppliesTo
+
+
+ Left
+ Scope
+
+
+ Left
+ HelpMessage
+
+
+
+
+
+
diff --git a/src/Accounts/Accounts/Az.Accounts.psd1 b/src/Accounts/Accounts/Az.Accounts.psd1
index d7dd612c46f9..c65400674670 100644
--- a/src/Accounts/Accounts/Az.Accounts.psd1
+++ b/src/Accounts/Accounts/Az.Accounts.psd1
@@ -108,7 +108,7 @@ CmdletsToExport = 'Disable-AzDataCollection', 'Disable-AzContextAutosave',
'Set-AzDefault', 'Get-AzDefault', 'Clear-AzDefault',
'Register-AzModule', 'Enable-AzureRmAlias', 'Disable-AzureRmAlias',
'Uninstall-AzureRm', 'Invoke-AzRestMethod', 'Get-AzAccessToken',
- 'Open-AzSurveyLink'
+ 'Open-AzSurveyLink', 'Get-AzConfig', 'Update-AzConfig', 'Clear-AzConfig'
# Variables to export from this module
# VariablesToExport = @()
diff --git a/src/Accounts/Accounts/ChangeLog.md b/src/Accounts/Accounts/ChangeLog.md
index a362893a602d..81aeda830ff1 100644
--- a/src/Accounts/Accounts/ChangeLog.md
+++ b/src/Accounts/Accounts/ChangeLog.md
@@ -19,6 +19,10 @@
-->
## Upcoming Release
+* Added a preview feature allowing user to control the configurations of Azure PowerShell by using the following cmdlets:
+ - `Get-AzConfig`
+ - `Update-AzConfig`
+ - `Clear-AzConfig`
* Upgraded System.Reflection.DispatchProxy on Windows PowerShell [#17856]
## Version 2.7.6
@@ -215,7 +219,7 @@
* Updated Add-AzEnvironment and Set-AzEnvironment to accept parameters AzureAttestationServiceEndpointResourceId and AzureAttestationServiceEndpointSuffix
## Version 1.6.6
-* Add client-side telemetry info for Az 4.0 preview
+* Add client-side telemetry info for Az 4.0 `preview`
## Version 1.6.5
* Update references in .psd1 to use relative path
diff --git a/src/Accounts/Accounts/Config/ClearConfigCommand.cs b/src/Accounts/Accounts/Config/ClearConfigCommand.cs
new file mode 100644
index 000000000000..f246db7495b2
--- /dev/null
+++ b/src/Accounts/Accounts/Config/ClearConfigCommand.cs
@@ -0,0 +1,114 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using Microsoft.Azure.PowerShell.Common.Config;
+using Microsoft.WindowsAzure.Commands.Common.CustomAttributes;
+using Microsoft.WindowsAzure.Commands.Utilities.Common;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Management.Automation;
+
+namespace Microsoft.Azure.Commands.Common.Authentication.Config
+{
+ [Cmdlet("Clear", "AzConfig", SupportsShouldProcess = true)]
+ [OutputType(typeof(bool))]
+ [CmdletPreview(PreviewMessage)]
+ public class ClearConfigCommand : ConfigCommandBase, IDynamicParameters
+ {
+ private const string ClearByKey = "ClearByKey";
+ private const string ClearAll = "ClearAll";
+
+ private const string ProcessMessage = "Clear the configs that apply to \"{0}\" by the following keys: {1}.";
+
+ private string ContinueMessage => $"Clear all the configs that apply to \"{AppliesTo}\" in scope {Scope}?";
+ private string ProcessTarget => $"Configs in scope {Scope}";
+
+ [Parameter(ParameterSetName = ClearAll, Mandatory = true, HelpMessage = "Clear all configs.")]
+ public SwitchParameter All { get; set; }
+
+ [Parameter(ParameterSetName = ClearAll, HelpMessage = "Do not ask for confirmation when clearing all configs.")]
+ public SwitchParameter Force { get; set; }
+
+ [Parameter(HelpMessage = "Returns true if cmdlet executes correctly.")]
+ public SwitchParameter PassThru { get; set; }
+
+ public new object GetDynamicParameters()
+ {
+ return GetDynamicParameters((ConfigDefinition config) =>
+ new RuntimeDefinedParameter(
+ config.Key,
+ typeof(SwitchParameter),
+ new Collection() {
+ new ParameterAttribute {
+ ParameterSetName = ClearByKey,
+ HelpMessage = config.HelpMessage
+ }
+ }));
+ }
+
+ public override void ExecuteCmdlet()
+ {
+ switch (ParameterSetName)
+ {
+ case ClearByKey:
+ ClearConfigByKey();
+ break;
+ case ClearAll:
+ ClearAllConfigs();
+ break;
+ }
+ if (PassThru)
+ {
+ WriteObject(true);
+ }
+ }
+
+ private void ClearConfigByKey()
+ {
+ IEnumerable configKeysFromInput = GetConfigsSpecifiedByUser()
+ .Where(x => (SwitchParameter)x.Value)
+ .Select(x => x.Key);
+ if (!configKeysFromInput.Any())
+ {
+ WriteWarning($"Please specify the key(s) of the configs to clear. Run `help {MyInvocation.MyCommand.Name}` for more information.");
+ return;
+ }
+ base.ConfirmAction(
+ string.Format(ProcessMessage, AppliesTo, string.Join(", ", configKeysFromInput)),
+ ProcessTarget,
+ () => configKeysFromInput.ForEach(ClearConfigByKey));
+ }
+
+ private void ClearConfigByKey(string key)
+ {
+ ConfigManager.ClearConfig(new ClearConfigOptions(key, Scope)
+ {
+ AppliesTo = AppliesTo
+ });
+ }
+
+ private void ClearAllConfigs()
+ {
+ ConfirmAction(Force, ContinueMessage, ContinueMessage, ProcessTarget, () =>
+ {
+ ConfigManager.ClearConfig(new ClearConfigOptions(null, Scope)
+ {
+ AppliesTo = AppliesTo
+ });
+ });
+ }
+ }
+}
diff --git a/src/Accounts/Accounts/Config/ConfigCommandBase.cs b/src/Accounts/Accounts/Config/ConfigCommandBase.cs
new file mode 100644
index 000000000000..058f53316a7c
--- /dev/null
+++ b/src/Accounts/Accounts/Config/ConfigCommandBase.cs
@@ -0,0 +1,98 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using Microsoft.Azure.Commands.Common.Exceptions;
+using Microsoft.Azure.Commands.ResourceManager.Common;
+using Microsoft.Azure.PowerShell.Common.Config;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Management.Automation;
+
+namespace Microsoft.Azure.Commands.Common.Authentication.Config
+{
+ public abstract class ConfigCommandBase : AzureRMCmdlet
+ {
+ protected const string PreviewMessage = "The cmdlet group \"AzConfig\" is in preview. Feedback is welcome: https://aka.ms/azpsissue";
+
+ private readonly RuntimeDefinedParameterDictionary _dynamicParameters = new RuntimeDefinedParameterDictionary();
+
+ protected IConfigManager ConfigManager { get; }
+ protected IEnumerable ConfigDefinitions
+ {
+ get
+ {
+ if (_configDefinitions == null)
+ {
+ _configDefinitions = ConfigManager.ListConfigDefinitions();
+ }
+ return _configDefinitions;
+ }
+ }
+ private IEnumerable _configDefinitions;
+
+ public ConfigCommandBase() : base()
+ {
+ if (!AzureSession.Instance.TryGetComponent(nameof(IConfigManager), out var configManager))
+ {
+ throw new AzPSApplicationException($"Unexpected error: {nameof(IConfigManager)} has not been registered to the current session.");
+ }
+ ConfigManager = configManager;
+ }
+
+ [Parameter(HelpMessage = "Specifies what part of Azure PowerShell the config applies to. Possible values are:\n- \"" + ConfigFilter.GlobalAppliesTo + "\": the config applies to all modules and cmdlets of Azure PowerShell. \n- Module name: the config applies to a certain module of Azure PowerShell. For example, \"Az.Storage\".\n- Cmdlet name: the config applies to a certain cmdlet of Azure PowerShell. For example, \"Get-AzKeyVault\".\nIf not specified, when getting configs, output will be all of the above; when updating, it defaults to \"" + ConfigFilter.GlobalAppliesTo + "\"; when clearing, configs applying to any targets are cleared.")]
+ [ValidateNotNullOrEmpty]
+ public string AppliesTo { get; set; }
+
+ [Parameter(HelpMessage = "Determines the scope of config changes, for example, whether changes apply only to the current process, or to all sessions started by this user. By default it is CurrentUser.")]
+ public ConfigScope Scope { get; set; } = ConfigScope.CurrentUser;
+
+ protected override void BeginProcessing()
+ {
+ base.BeginProcessing();
+ ValidateParameters();
+ }
+
+ protected virtual void ValidateParameters()
+ {
+ if (!AppliesToHelper.TryParseAppliesTo(AppliesTo, out _))
+ {
+ throw new AzPSArgumentException($"{nameof(AppliesTo)} must be a valid module name, a cmdlet name, or \"{ConfigFilter.GlobalAppliesTo}\"", nameof(AppliesTo));
+ }
+ }
+
+ protected object GetDynamicParameters(Func mapConfigToParameter)
+ {
+ _dynamicParameters.Clear();
+ foreach (var config in ConfigDefinitions)
+ {
+ _dynamicParameters.Add(config.Key, mapConfigToParameter(config));
+ }
+ return _dynamicParameters;
+ }
+
+ ///
+ /// Gets the dynamic parameters and their values if specified.
+ ///
+ ///
+ protected IEnumerable<(string Key, object Value)> GetConfigsSpecifiedByUser()
+ {
+ var configs = new Dictionary();
+ foreach (var param in _dynamicParameters.Values.Where(p => p.IsSet))
+ {
+ yield return (param.Name, param.Value);
+ }
+ }
+ }
+}
diff --git a/src/Accounts/Accounts/Config/GetConfigCommand.cs b/src/Accounts/Accounts/Config/GetConfigCommand.cs
new file mode 100644
index 000000000000..b285b9b1f544
--- /dev/null
+++ b/src/Accounts/Accounts/Config/GetConfigCommand.cs
@@ -0,0 +1,71 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using Microsoft.Azure.Commands.Profile.Models;
+using Microsoft.Azure.Commands.ResourceManager.Common;
+using Microsoft.Azure.PowerShell.Common.Config;
+using Microsoft.WindowsAzure.Commands.Common.CustomAttributes;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Management.Automation;
+
+namespace Microsoft.Azure.Commands.Common.Authentication.Config
+{
+ [Cmdlet(VerbsCommon.Get, AzureRMConstants.AzureRMPrefix + "Config")]
+ [OutputType(typeof(PSConfig))]
+ [CmdletPreview(PreviewMessage)]
+ public class GetConfigCommand : ConfigCommandBase, IDynamicParameters
+ {
+ public GetConfigCommand() : base()
+ {
+ }
+
+ public new object GetDynamicParameters()
+ {
+ return GetDynamicParameters((ConfigDefinition config) =>
+ new RuntimeDefinedParameter(
+ config.Key,
+ typeof(SwitchParameter),
+ new Collection() {
+ new ParameterAttribute {
+ HelpMessage = config.HelpMessage
+ }
+ }));
+ }
+
+ public override void ExecuteCmdlet()
+ {
+ ConfigFilter filter = CreateConfigFilter();
+
+ IEnumerable configs = ConfigManager.ListConfigs(filter);
+ WriteObject(configs.Select(x => new PSConfig(x)), true);
+ }
+
+ private ConfigFilter CreateConfigFilter()
+ {
+ ConfigFilter filter = new ConfigFilter() { AppliesTo = AppliesTo };
+ IEnumerable configKeysFromInput = GetConfigsSpecifiedByUser()
+ .Where(x => (SwitchParameter)x.Value)
+ .Select(x => x.Key);
+ if (configKeysFromInput.Any())
+ {
+ filter.Keys = configKeysFromInput;
+ }
+
+ return filter;
+ }
+ }
+}
diff --git a/src/Accounts/Accounts/Config/UpdateConfigCommand.cs b/src/Accounts/Accounts/Config/UpdateConfigCommand.cs
new file mode 100644
index 000000000000..c1946b6099e7
--- /dev/null
+++ b/src/Accounts/Accounts/Config/UpdateConfigCommand.cs
@@ -0,0 +1,78 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using Microsoft.Azure.Commands.Profile.Models;
+using Microsoft.Azure.PowerShell.Common.Config;
+using Microsoft.WindowsAzure.Commands.Common.CustomAttributes;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Management.Automation;
+
+namespace Microsoft.Azure.Commands.Common.Authentication.Config
+{
+ [Cmdlet("Update", "AzConfig", SupportsShouldProcess = true)]
+ [OutputType(typeof(PSConfig))]
+ [CmdletPreview(PreviewMessage)]
+ public class UpdateConfigCommand : ConfigCommandBase, IDynamicParameters
+ {
+ private const string ProcessMessage = "Update the configs that apply to \"{0}\" by the following keys: {1}.";
+ private string ProcessTarget => $"Configs in scope {Scope}";
+
+ public new object GetDynamicParameters() => GetDynamicParameters(
+ (ConfigDefinition config) => new RuntimeDefinedParameter(
+ config.Key, config.ValueType,
+ new Collection() { new ParameterAttribute {
+ HelpMessage = config.HelpMessage,
+ ValueFromPipelineByPropertyName = true
+ } }
+ ));
+
+ protected override void BeginProcessing()
+ {
+ base.BeginProcessing();
+ if (AppliesTo == null)
+ {
+ AppliesTo = ConfigFilter.GlobalAppliesTo;
+ }
+ }
+
+ public override void ExecuteCmdlet()
+ {
+ var configsFromInput = GetConfigsSpecifiedByUser();
+ if (!configsFromInput.Any())
+ {
+ WriteWarning($"Please specify the key(s) of the configs to update. Run `help {MyInvocation.MyCommand.Name}` for more information.");
+ return;
+ }
+ base.ConfirmAction(
+ string.Format(ProcessMessage, AppliesTo, string.Join(", ", configsFromInput.Select(x => x.Key))),
+ ProcessTarget,
+ () => UpdateConfigs(configsFromInput));
+ }
+
+ private void UpdateConfigs(IEnumerable<(string, object)> configsToUpdate)
+ {
+ foreach ((string key, object value) in configsToUpdate)
+ {
+ ConfigData updated = ConfigManager.UpdateConfig(new UpdateConfigOptions(key, value, Scope)
+ {
+ AppliesTo = AppliesTo
+ });
+ WriteObject(new PSConfig(updated));
+ }
+ }
+ }
+}
diff --git a/src/Accounts/Accounts/Directory.Build.targets b/src/Accounts/Accounts/Directory.Build.targets
index fa3748d4339a..278dd06f9a08 100644
--- a/src/Accounts/Accounts/Directory.Build.targets
+++ b/src/Accounts/Accounts/Directory.Build.targets
@@ -1,9 +1,10 @@
-
+
+
-
+
diff --git a/src/Accounts/Accounts/Models/PSConfig.cs b/src/Accounts/Accounts/Models/PSConfig.cs
new file mode 100644
index 000000000000..c211a8fb7d02
--- /dev/null
+++ b/src/Accounts/Accounts/Models/PSConfig.cs
@@ -0,0 +1,42 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using Microsoft.Azure.PowerShell.Common.Config;
+
+namespace Microsoft.Azure.Commands.Profile.Models
+{
+ ///
+ /// The output model of config-related cmdlets.
+ ///
+ public class PSConfig
+ {
+ public string Key { get; }
+ public object Value { get; }
+ public ConfigScope Scope { get; } = ConfigScope.CurrentUser;
+ public string AppliesTo { get; }
+ public string HelpMessage { get; }
+ public object DefaultValue { get; }
+ public PSConfig(ConfigData config)
+ {
+ Value = config.Value;
+ Scope = config.Scope;
+ AppliesTo = config.AppliesTo;
+
+ var def = config.Definition;
+ Key = def.Key;
+ HelpMessage = def.HelpMessage;
+ DefaultValue = def.DefaultValue;
+ }
+ }
+}
diff --git a/src/Accounts/Accounts/help/Az.Accounts.md b/src/Accounts/Accounts/help/Az.Accounts.md
index c05e40b851cb..351244e89071 100644
--- a/src/Accounts/Accounts/help/Az.Accounts.md
+++ b/src/Accounts/Accounts/help/Az.Accounts.md
@@ -14,6 +14,9 @@ Manages credentials and common configuration for all Azure modules.
### [Add-AzEnvironment](Add-AzEnvironment.md)
Adds endpoints and metadata for an instance of Azure Resource Manager.
+### [Clear-AzConfig](Clear-AzConfig.md)
+Clears the values of configs that are set by the user.
+
### [Clear-AzContext](Clear-AzContext.md)
Remove all Azure credentials, account, and subscription information.
@@ -56,6 +59,9 @@ Enables AzureRm prefix aliases for Az modules.
### [Get-AzAccessToken](Get-AzAccessToken.md)
Get raw access token. When using -ResourceUrl, please make sure the value does match current Azure environment. You may refer to the value of `(Get-AzContext).Environment`.
+### [Get-AzConfig](Get-AzConfig.md)
+Gets the configs of Azure PowerShell.
+
### [Get-AzContext](Get-AzContext.md)
Gets the metadata used to authenticate Azure Resource Manager requests.
@@ -120,3 +126,6 @@ Sets properties for an Azure environment.
### [Uninstall-AzureRm](Uninstall-AzureRm.md)
Removes all AzureRm modules from a machine.
+### [Update-AzConfig](Update-AzConfig.md)
+Updates the configs of Azure PowerShell.
+
diff --git a/src/Accounts/Accounts/help/Clear-AzConfig.md b/src/Accounts/Accounts/help/Clear-AzConfig.md
new file mode 100644
index 000000000000..55ea44291f4c
--- /dev/null
+++ b/src/Accounts/Accounts/help/Clear-AzConfig.md
@@ -0,0 +1,251 @@
+---
+external help file: Microsoft.Azure.PowerShell.Cmdlets.Accounts.dll-Help.xml
+Module Name: Az.Accounts
+online version: https://docs.microsoft.com/powershell/module/az.accounts/clear-azconfig
+schema: 2.0.0
+---
+
+# Clear-AzConfig
+
+## SYNOPSIS
+Clears the values of configs that are set by the user.
+
+## SYNTAX
+
+### ClearAll
+```
+Clear-AzConfig [-All] [-Force] [-PassThru] [-AppliesTo ] [-Scope ]
+ [-DefaultProfile ] [-WhatIf] [-Confirm] []
+```
+
+### ClearByKey
+```
+Clear-AzConfig [-PassThru] [-AppliesTo ] [-Scope ]
+ [-DefaultProfile ] [-WhatIf] [-Confirm] [-DefaultSubscriptionForLogin]
+ [-EnableDataCollection] [-EnableInterceptSurvey] [-SuppressWarningMessage] []
+```
+
+## DESCRIPTION
+{{ Fill in the Description }}
+
+## EXAMPLES
+
+### Example 1
+```powershell
+Clear-AzConfig -Todo
+```
+
+```output
+Todo
+```
+
+Todo
+
+## PARAMETERS
+
+### -All
+Clear all configs.
+
+```yaml
+Type: System.Management.Automation.SwitchParameter
+Parameter Sets: ClearAll
+Aliases:
+
+Required: True
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -AppliesTo
+Specifies what part of Azure PowerShell the config applies to.
+Possible values are:
+- "Az": the config applies to all modules and cmdlets of Azure PowerShell.
+- Module name: the config applies to a certain module of Azure PowerShell.
+For example, "Az.Storage".
+- Cmdlet name: the config applies to a certain cmdlet of Azure PowerShell.
+For example, "Get-AzKeyVault".
+If not specified, when getting configs, output will be all of the above; when updating or clearing configs, it defaults to "Az"
+
+```yaml
+Type: System.String
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -DefaultProfile
+The credentials, account, tenant, and subscription used for communication with Azure.
+
+```yaml
+Type: Microsoft.Azure.Commands.Common.Authentication.Abstractions.Core.IAzureContextContainer
+Parameter Sets: (All)
+Aliases: AzContext, AzureRmContext, AzureCredential
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -DefaultSubscriptionForLogin
+Subscription name or GUID.
+If defined, when logging in Azure PowerShell without specifying the subscription, this one will be used to select the default context.
+
+```yaml
+Type: System.Management.Automation.SwitchParameter
+Parameter Sets: ClearByKey
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -EnableDataCollection
+todo
+
+```yaml
+Type: System.Management.Automation.SwitchParameter
+Parameter Sets: ClearByKey
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -EnableInterceptSurvey
+When enabled, a message of taking part in the survey about the user experience of Azure PowerShell will prompt at low frequency.
+
+```yaml
+Type: System.Management.Automation.SwitchParameter
+Parameter Sets: ClearByKey
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -Force
+Do not ask for confirmation when clearing all configs.
+
+```yaml
+Type: System.Management.Automation.SwitchParameter
+Parameter Sets: ClearAll
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -PassThru
+Returns true if cmdlet executes correctly.
+
+```yaml
+Type: System.Management.Automation.SwitchParameter
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -Scope
+Determines the scope of config changes, for example, whether changes apply only to the current process, or to all sessions started by this user.
+By default it is CurrentUser.
+
+```yaml
+Type: Microsoft.Azure.PowerShell.Common.Config.ConfigScope
+Parameter Sets: (All)
+Aliases:
+Accepted values: CurrentUser, Process, Default
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -SuppressWarningMessage
+Controls if the warning messages of upcoming breaking changes are enabled or suppressed.
+The messages are typically displayed when a cmdlet that will have breaking change in the future is executed.
+
+```yaml
+Type: System.Management.Automation.SwitchParameter
+Parameter Sets: ClearByKey
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -Confirm
+Prompts you for confirmation before running the cmdlet.
+
+```yaml
+Type: System.Management.Automation.SwitchParameter
+Parameter Sets: (All)
+Aliases: cf
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -WhatIf
+Shows what would happen if the cmdlet runs.
+The cmdlet is not run.
+
+```yaml
+Type: System.Management.Automation.SwitchParameter
+Parameter Sets: (All)
+Aliases: wi
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### CommonParameters
+This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
+
+## INPUTS
+
+### None
+
+## OUTPUTS
+
+### System.Boolean
+
+## NOTES
+
+## RELATED LINKS
diff --git a/src/Accounts/Accounts/help/Get-AzConfig.md b/src/Accounts/Accounts/help/Get-AzConfig.md
new file mode 100644
index 000000000000..f51d073b6ea4
--- /dev/null
+++ b/src/Accounts/Accounts/help/Get-AzConfig.md
@@ -0,0 +1,168 @@
+---
+external help file: Microsoft.Azure.PowerShell.Cmdlets.Accounts.dll-Help.xml
+Module Name: Az.Accounts
+online version: https://docs.microsoft.com/powershell/module/az.accounts/get-azconfig
+schema: 2.0.0
+---
+
+# Get-AzConfig
+
+## SYNOPSIS
+Gets the configs of Azure PowerShell.
+
+## SYNTAX
+
+```
+Get-AzConfig [-AppliesTo ] [-Scope ] [-DefaultProfile ]
+ [-DefaultSubscriptionForLogin] [-EnableDataCollection] [-EnableInterceptSurvey] [-SuppressWarningMessage]
+ []
+```
+
+## DESCRIPTION
+{{ Fill in the Description }}
+
+## EXAMPLES
+
+### Example 1
+```powershell
+Get-AzConfig
+```
+
+```output
+Todo
+```
+
+Todo
+
+## PARAMETERS
+
+### -AppliesTo
+Specifies what part of Azure PowerShell the config applies to.
+Possible values are:
+- "Az": the config applies to all modules and cmdlets of Azure PowerShell.
+- Module name: the config applies to a certain module of Azure PowerShell.
+For example, "Az.Storage".
+- Cmdlet name: the config applies to a certain cmdlet of Azure PowerShell.
+For example, "Get-AzKeyVault".
+If not specified, when getting configs, output will be all of the above; when updating or clearing configs, it defaults to "Az"
+
+```yaml
+Type: System.String
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -DefaultProfile
+The credentials, account, tenant, and subscription used for communication with Azure.
+
+```yaml
+Type: Microsoft.Azure.Commands.Common.Authentication.Abstractions.Core.IAzureContextContainer
+Parameter Sets: (All)
+Aliases: AzContext, AzureRmContext, AzureCredential
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -DefaultSubscriptionForLogin
+Subscription name or GUID.
+If defined, when logging in Azure PowerShell without specifying the subscription, this one will be used to select the default context.
+
+```yaml
+Type: System.Management.Automation.SwitchParameter
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -EnableDataCollection
+todo
+
+```yaml
+Type: System.Management.Automation.SwitchParameter
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -EnableInterceptSurvey
+When enabled, a message of taking part in the survey about the user experience of Azure PowerShell will prompt at low frequency.
+
+```yaml
+Type: System.Management.Automation.SwitchParameter
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -Scope
+Determines the scope of config changes, for example, whether changes apply only to the current process, or to all sessions started by this user.
+By default it is CurrentUser.
+
+```yaml
+Type: Microsoft.Azure.PowerShell.Common.Config.ConfigScope
+Parameter Sets: (All)
+Aliases:
+Accepted values: CurrentUser, Process, Default
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -SuppressWarningMessage
+Controls if the warning messages of upcoming breaking changes are enabled or suppressed.
+The messages are typically displayed when a cmdlet that will have breaking change in the future is executed.
+
+```yaml
+Type: System.Management.Automation.SwitchParameter
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### CommonParameters
+This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
+
+## INPUTS
+
+### None
+
+## OUTPUTS
+
+### Microsoft.Azure.Commands.Common.Authentication.Config.PSConfig
+
+## NOTES
+
+## RELATED LINKS
diff --git a/src/Accounts/Accounts/help/Update-AzConfig.md b/src/Accounts/Accounts/help/Update-AzConfig.md
new file mode 100644
index 000000000000..a67982f7051f
--- /dev/null
+++ b/src/Accounts/Accounts/help/Update-AzConfig.md
@@ -0,0 +1,199 @@
+---
+external help file: Microsoft.Azure.PowerShell.Cmdlets.Accounts.dll-Help.xml
+Module Name: Az.Accounts
+online version: https://docs.microsoft.com/powershell/module/az.accounts/update-azconfig
+schema: 2.0.0
+---
+
+# Update-AzConfig
+
+## SYNOPSIS
+Updates the configs of Azure PowerShell.
+
+## SYNTAX
+
+```
+Update-AzConfig [-AppliesTo ] [-Scope ] [-DefaultProfile ]
+ [-WhatIf] [-Confirm] [-DefaultSubscriptionForLogin ] [-EnableDataCollection ]
+ [-EnableInterceptSurvey ] [-SuppressWarningMessage ] []
+```
+
+## DESCRIPTION
+{{ Fill in the Description }}
+
+## EXAMPLES
+
+### Example 1
+```powershell
+Update-AzConfig -Todo $true
+```
+
+```output
+Todo
+```
+
+Todo
+
+## PARAMETERS
+
+### -AppliesTo
+Specifies what part of Azure PowerShell the config applies to.
+Possible values are:
+- "Az": the config applies to all modules and cmdlets of Azure PowerShell.
+- Module name: the config applies to a certain module of Azure PowerShell.
+For example, "Az.Storage".
+- Cmdlet name: the config applies to a certain cmdlet of Azure PowerShell.
+For example, "Get-AzKeyVault".
+If not specified, when getting configs, output will be all of the above; when updating or clearing configs, it defaults to "Az"
+
+```yaml
+Type: System.String
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -DefaultProfile
+The credentials, account, tenant, and subscription used for communication with Azure.
+
+```yaml
+Type: Microsoft.Azure.Commands.Common.Authentication.Abstractions.Core.IAzureContextContainer
+Parameter Sets: (All)
+Aliases: AzContext, AzureRmContext, AzureCredential
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -DefaultSubscriptionForLogin
+Subscription name or GUID.
+If defined, when logging in Azure PowerShell without specifying the subscription, this one will be used to select the default context.
+
+```yaml
+Type: System.String
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: True (ByPropertyName)
+Accept wildcard characters: False
+```
+
+### -EnableDataCollection
+todo
+
+```yaml
+Type: System.Boolean
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: True (ByPropertyName)
+Accept wildcard characters: False
+```
+
+### -EnableInterceptSurvey
+When enabled, a message of taking part in the survey about the user experience of Azure PowerShell will prompt at low frequency.
+
+```yaml
+Type: System.Boolean
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: True (ByPropertyName)
+Accept wildcard characters: False
+```
+
+### -Scope
+Determines the scope of config changes, for example, whether changes apply only to the current process, or to all sessions started by this user.
+By default it is CurrentUser.
+
+```yaml
+Type: Microsoft.Azure.PowerShell.Common.Config.ConfigScope
+Parameter Sets: (All)
+Aliases:
+Accepted values: CurrentUser, Process, Default
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -SuppressWarningMessage
+Controls if the warning messages of upcoming breaking changes are enabled or suppressed.
+The messages are typically displayed when a cmdlet that will have breaking change in the future is executed.
+
+```yaml
+Type: System.Boolean
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: True (ByPropertyName)
+Accept wildcard characters: False
+```
+
+### -Confirm
+Prompts you for confirmation before running the cmdlet.
+
+```yaml
+Type: System.Management.Automation.SwitchParameter
+Parameter Sets: (All)
+Aliases: cf
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -WhatIf
+Shows what would happen if the cmdlet runs.
+The cmdlet is not run.
+
+```yaml
+Type: System.Management.Automation.SwitchParameter
+Parameter Sets: (All)
+Aliases: wi
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### CommonParameters
+This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
+
+## INPUTS
+
+### None
+
+## OUTPUTS
+
+### Microsoft.Azure.Commands.Common.Authentication.Config.PSConfig
+
+## NOTES
+
+## RELATED LINKS
diff --git a/src/Accounts/Authentication.Test/ConfigTests/ClearConfigTests.cs b/src/Accounts/Authentication.Test/ConfigTests/ClearConfigTests.cs
new file mode 100644
index 000000000000..b9fbba072cf6
--- /dev/null
+++ b/src/Accounts/Authentication.Test/ConfigTests/ClearConfigTests.cs
@@ -0,0 +1,214 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using Microsoft.Azure.Commands.Common.Exceptions;
+using Microsoft.Azure.Commands.Common.Authentication.Config;
+using Microsoft.Azure.PowerShell.Common.Config;
+using Microsoft.Rest.ClientRuntime.Azure.TestFramework;
+using Microsoft.VisualStudio.TestPlatform.ObjectModel;
+using Xunit;
+
+namespace Microsoft.Azure.Authentication.Test.Config
+{
+ public class ClearConfigTests : ConfigTestsBase
+ {
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanClearSingleConfig()
+ {
+ string key = "FalseByDefault";
+ IConfigManager icm = GetConfigManager(new SimpleTypedConfig(key, "{help message}", false));
+ Assert.False(icm.GetConfigValue(key));
+
+ icm.UpdateConfig(new UpdateConfigOptions(key, true, ConfigScope.Process));
+ Assert.True(icm.GetConfigValue(key));
+
+ icm.ClearConfig(new ClearConfigOptions(key, ConfigScope.Process));
+ Assert.False(icm.GetConfigValue(key));
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CannotClearUnknownConfig()
+ {
+ IConfigManager configurationManager = GetConfigManager();
+
+ Assert.Throws(() =>
+ {
+ configurationManager.ClearConfig(new ClearConfigOptions("NeverRegistered", ConfigScope.CurrentUser));
+ });
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void ShouldNotThrowToClearConfigNeverSet()
+ {
+ string key1 = "key1";
+ var config1 = new SimpleTypedConfig(key1, "{help message}", false);
+ string key2 = "key2";
+ var config2 = new SimpleTypedConfig(key2, "{help message}", false);
+ IConfigManager icm = GetConfigManager(config1, config2);
+
+ icm.ClearConfig(key1, ConfigScope.CurrentUser);
+ icm.ClearConfig(key2, ConfigScope.Process);
+ icm.ClearConfig(null, ConfigScope.CurrentUser);
+ icm.ClearConfig(null, ConfigScope.Process);
+ icm.ClearConfig(new ClearConfigOptions(null, ConfigScope.CurrentUser)
+ {
+ AppliesTo = null
+ });
+ icm.ClearConfig(new ClearConfigOptions(null, ConfigScope.Process)
+ {
+ AppliesTo = null
+ });
+ icm.ClearConfig(new ClearConfigOptions(null, ConfigScope.CurrentUser)
+ {
+ AppliesTo = "Az.Accounts"
+ });
+ icm.ClearConfig(new ClearConfigOptions(null, ConfigScope.Process)
+ {
+ AppliesTo = "Az.Accounts"
+ });
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanClearSingleConfigInJson()
+ {
+ IConfigManager icm = GetConfigManager();
+ string key = "DisableSomething";
+ icm.RegisterConfig(new SimpleTypedConfig(key, "{help message}", false));
+ icm.BuildConfig();
+
+ Assert.False(icm.GetConfigValue(key));
+
+ icm.UpdateConfig(new UpdateConfigOptions(key, true, ConfigScope.CurrentUser));
+ Assert.True(icm.GetConfigValue(key));
+
+ icm.ClearConfig(new ClearConfigOptions(key, ConfigScope.CurrentUser));
+ Assert.False(icm.GetConfigValue(key));
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanClearAllConfigsInJson()
+ {
+ string key1 = "key1";
+ var config1 = new SimpleTypedConfig(key1, "{help message}", false);
+ string key2 = "key2";
+ var config2 = new SimpleTypedConfig(key2, "{help message}", false);
+ ConfigManager cm = GetConfigManager(config1, config2) as ConfigManager;
+
+ Assert.False(cm.GetConfigValue(key1));
+ Assert.False(cm.GetConfigValue(key2));
+
+ // Scenario 1: update the configs, applying to Az
+ cm.UpdateConfig(new UpdateConfigOptions(key1, true, ConfigScope.CurrentUser));
+ Assert.True(cm.GetConfigValue(key1));
+ cm.UpdateConfig(new UpdateConfigOptions(key2, true, ConfigScope.CurrentUser));
+ Assert.True(cm.GetConfigValue(key2));
+
+ // clear all configs by specifying `null` as the key, applying to Az
+ cm.ClearConfig(null, ConfigScope.CurrentUser);
+ Assert.False(cm.GetConfigValue(key1));
+ Assert.False(cm.GetConfigValue(key2));
+
+ // Scenario 2: update the configs, applying to Az.Accounts
+ cm.UpdateConfig(new UpdateConfigOptions(key1, true, ConfigScope.CurrentUser) { AppliesTo = "Az.Accounts" });
+ Assert.True(cm.GetConfigValueInternal(key1, new InternalInvocationInfo() { ModuleName = "Az.Accounts" }));
+ cm.UpdateConfig(new UpdateConfigOptions(key2, true, ConfigScope.CurrentUser) { AppliesTo = "Az.Accounts" });
+ Assert.True(cm.GetConfigValueInternal(key2, new InternalInvocationInfo() { ModuleName = "Az.Accounts" }));
+
+ // clear all configs, applying to Az.Accounts
+ cm.ClearConfig(new ClearConfigOptions(null, ConfigScope.CurrentUser) { AppliesTo = "Az.Accounts" });
+ Assert.False(cm.GetConfigValueInternal(key1, new InternalInvocationInfo() { ModuleName = "Az.Accounts" }));
+ Assert.False(cm.GetConfigValueInternal(key2, new InternalInvocationInfo() { ModuleName = "Az.Accounts" }));
+
+ // Scenario 3: update the configs, applying differently
+ cm.UpdateConfig(new UpdateConfigOptions(key1, true, ConfigScope.CurrentUser) { AppliesTo = "Az.Accounts" });
+ Assert.True(cm.GetConfigValueInternal(key1, new InternalInvocationInfo() { ModuleName = "Az.Accounts" }));
+ cm.UpdateConfig(new UpdateConfigOptions(key2, true, ConfigScope.CurrentUser) { AppliesTo = "Az.KeyVault" });
+ Assert.True(cm.GetConfigValueInternal(key2, new InternalInvocationInfo() { ModuleName = "Az.KeyVault" }));
+
+ // clear all configs, applying anything
+ cm.ClearConfig(null, ConfigScope.CurrentUser);
+ Assert.False(cm.GetConfigValueInternal(key1, new InternalInvocationInfo() { ModuleName = "Az.Accounts" }));
+ Assert.False(cm.GetConfigValueInternal(key2, new InternalInvocationInfo() { ModuleName = "Az.KeyVault" }));
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void ShouldNotThrowWhenClearConfigNeverSet()
+ {
+ string key = "DisableSomething";
+ var config = new SimpleTypedConfig(key, "{help message}", false);
+ IConfigManager icm = GetConfigManager(config);
+
+ icm.ClearConfig(key, ConfigScope.CurrentUser);
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanClearByScope()
+ {
+ const string boolKey = "BoolKey";
+ var boolConfig = new SimpleTypedConfig(boolKey, "", false);
+ const string intKey = "intKey";
+ var intConfig = new SimpleTypedConfig(intKey, "", 0);
+ var icm = GetConfigManager(boolConfig, intConfig);
+
+ icm.UpdateConfig(new UpdateConfigOptions(boolKey, true, ConfigScope.CurrentUser));
+ icm.UpdateConfig(new UpdateConfigOptions(intKey, 10, ConfigScope.CurrentUser));
+ icm.UpdateConfig(new UpdateConfigOptions(boolKey, true, ConfigScope.Process));
+ icm.UpdateConfig(new UpdateConfigOptions(intKey, 10, ConfigScope.Process));
+
+ icm.ClearConfig(new ClearConfigOptions(boolKey, ConfigScope.Process));
+ icm.ClearConfig(new ClearConfigOptions(intKey, ConfigScope.Process));
+
+ foreach (var configData in icm.ListConfigs())
+ {
+ Assert.NotEqual(ConfigScope.Process, configData.Scope);
+ }
+
+ icm.ClearConfig(boolKey, ConfigScope.CurrentUser);
+ icm.ClearConfig(intKey, ConfigScope.CurrentUser);
+
+ foreach (var configData in icm.ListConfigs())
+ {
+ Assert.NotEqual(ConfigScope.CurrentUser, configData.Scope);
+ }
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void AppliesToShouldDefaultToAz()
+ {
+ const string boolKey = "BoolKey";
+ var boolConfig = new SimpleTypedConfig(boolKey, "", false);
+ var icm = GetConfigManager(boolConfig);
+
+ const string appliesTo = "Az.A";
+ icm.UpdateConfig(new UpdateConfigOptions(boolKey, true, ConfigScope.CurrentUser)
+ {
+ AppliesTo = appliesTo
+ });
+
+ icm.ClearConfig(boolKey, ConfigScope.CurrentUser);
+ Assert.Single(icm.ListConfigs(new ConfigFilter() { Keys = new string[] { boolKey }, AppliesTo = appliesTo }));
+
+ icm.ClearConfig(new ClearConfigOptions(boolKey, ConfigScope.CurrentUser) { AppliesTo = appliesTo });
+ Assert.Empty(icm.ListConfigs(new ConfigFilter() { Keys = new string[] { boolKey }, AppliesTo = appliesTo }));
+ }
+ }
+}
diff --git a/src/Accounts/Authentication.Test/ConfigTests/ConfigDefinitionTests.cs b/src/Accounts/Authentication.Test/ConfigTests/ConfigDefinitionTests.cs
new file mode 100644
index 000000000000..b451c1bea556
--- /dev/null
+++ b/src/Accounts/Authentication.Test/ConfigTests/ConfigDefinitionTests.cs
@@ -0,0 +1,60 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using Microsoft.Azure.Commands.Common.Exceptions;
+using Microsoft.Azure.Commands.Common.Authentication.Config;
+using Microsoft.Rest.ClientRuntime.Azure.TestFramework;
+using Microsoft.WindowsAzure.Commands.Common;
+using System;
+using System.Linq;
+using Xunit;
+using Microsoft.Azure.PowerShell.Common.Config;
+
+namespace Microsoft.Azure.Authentication.Test.Config
+{
+ public class ConfigDefinitionTests : ConfigTestsBase
+ {
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanValidateInput() {
+ const string boolKey = "BoolKey";
+ var boolConfig = new SimpleTypedConfig(boolKey, "", false);
+ var rangedIntConfig = new RangedConfig();
+ var icm = GetConfigManagerWithInitState(null, null, boolConfig, rangedIntConfig);
+
+ Assert.Throws(() => { icm.UpdateConfig(boolKey, 0, ConfigScope.CurrentUser); });
+ Assert.Throws(() => { icm.UpdateConfig(rangedIntConfig.Key, true, ConfigScope.CurrentUser); });
+ Assert.Throws(() => { icm.UpdateConfig(rangedIntConfig.Key, -1, ConfigScope.CurrentUser); });
+ }
+
+ private class RangedConfig : TypedConfig
+ {
+ public override object DefaultValue => 0;
+
+ public override string Key => "RangedKey";
+
+ public override string HelpMessage => "";
+
+ public override void Validate(object value)
+ {
+ base.Validate(value);
+ int valueAsInt = (int)value;
+ if (valueAsInt < 0 || valueAsInt > 100)
+ {
+ throw new ArgumentOutOfRangeException($"The value of config {Key} must be in between 0 and 100.");
+ }
+ }
+ }
+ }
+}
diff --git a/src/Accounts/Authentication.Test/ConfigTests/ConfigTestsBase.cs b/src/Accounts/Authentication.Test/ConfigTests/ConfigTestsBase.cs
new file mode 100644
index 000000000000..771641cee939
--- /dev/null
+++ b/src/Accounts/Authentication.Test/ConfigTests/ConfigTestsBase.cs
@@ -0,0 +1,75 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using Microsoft.Azure.Commands.Common.Authentication.Config;
+using Microsoft.Azure.PowerShell.Authentication.Test.Mocks;
+using Microsoft.Azure.PowerShell.Common.Config;
+using Microsoft.WindowsAzure.Commands.Common.Test.Mocks;
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Microsoft.Azure.Authentication.Test.Config
+{
+ public class ConfigTestsBase
+ {
+ private readonly Action _noopFileWriter = (x, y) => { };
+ private readonly Action _noopEnvVarWriter = (x) => { };
+
+ ///
+ /// Initializes and returns an with the specified configs registered.
+ ///
+ /// Definitions of configs to be registered to the config manager.
+ /// A config manager ready to use.
+ protected IConfigManager GetConfigManager(params ConfigDefinition[] config) => GetConfigManagerWithInitState(null, null, config);
+
+ ///
+ /// Initializes and returns an with the specified configs registered with initial state.
+ ///
+ /// An action to set up the config file before config manager initializes.
+ /// An action to set up the environments before config manager initializes.
+ /// Definitions of configs to be registered to the config manager.
+ /// A config manager with initial state, ready to use.
+ protected IConfigManager GetConfigManagerWithInitState(Action configFileWriter, Action envVarWriter, params ConfigDefinition[] config)
+ {
+ if (configFileWriter == null)
+ {
+ configFileWriter = _noopFileWriter;
+ }
+
+ if (envVarWriter == null)
+ {
+ envVarWriter = _noopEnvVarWriter;
+ }
+
+ string configPath = Path.GetRandomFileName();
+ var mockDataStore = new MockDataStore();
+ configFileWriter(mockDataStore, configPath);
+ var environmentVariables = new MockEnvironmentVariableProvider();
+ envVarWriter(environmentVariables);
+ ConfigInitializer ci = new ConfigInitializer(new List() { configPath })
+ {
+ DataStore = mockDataStore,
+ EnvironmentVariableProvider = environmentVariables
+ };
+ IConfigManager icm = ci.GetConfigManager();
+ foreach (var configDefinition in config)
+ {
+ icm.RegisterConfig(configDefinition);
+ }
+ icm.BuildConfig();
+ return icm;
+ }
+ }
+}
diff --git a/src/Accounts/Authentication.Test/ConfigTests/GetConfigTests.cs b/src/Accounts/Authentication.Test/ConfigTests/GetConfigTests.cs
new file mode 100644
index 000000000000..a1366a550dac
--- /dev/null
+++ b/src/Accounts/Authentication.Test/ConfigTests/GetConfigTests.cs
@@ -0,0 +1,339 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using Microsoft.Azure.Commands.Common.Exceptions;
+using Microsoft.Azure.Commands.Common.Authentication.Config;
+using Microsoft.Azure.PowerShell.Common.Config;
+using Microsoft.Rest.ClientRuntime.Azure.TestFramework;
+using System.Linq;
+using Xunit;
+
+namespace Microsoft.Azure.Authentication.Test.Config
+{
+ public class GetConfigTests : ConfigTestsBase
+ {
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanGetAppliesTo()
+ {
+ const string key = "EnableTelemetry";
+ var def = new SimpleTypedConfig(
+ key,
+ "Enable telemetry",
+ true);
+ IConfigManager icm = GetConfigManager(def);
+
+ var config = icm.ListConfigs().Single();
+ Assert.NotNull(config);
+ Assert.Equal(key, config.Definition.Key);
+
+ icm.UpdateConfig(new UpdateConfigOptions(key, false, ConfigScope.CurrentUser));
+ config = icm.ListConfigs().Single();
+ Assert.Equal(ConfigFilter.GlobalAppliesTo, config.AppliesTo);
+
+ icm.UpdateConfig(new UpdateConfigOptions(key, false, ConfigScope.CurrentUser) { AppliesTo = "Az.KeyVault" });
+ config = icm.ListConfigs(new ConfigFilter() { AppliesTo = "Az.KeyVault" }).Single();
+ Assert.Equal("Az.KeyVault", config.AppliesTo);
+
+ icm.UpdateConfig(new UpdateConfigOptions(key, false, ConfigScope.CurrentUser) { AppliesTo = "Get-AzKeyVault" });
+ config = icm.ListConfigs(new ConfigFilter { AppliesTo = "Get-AzKeyVault" }).Single();
+ Assert.Equal("Get-AzKeyVault", config.AppliesTo);
+
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void ShouldReturnEmptyWhenFilterIsWrong()
+ {
+ const string key = "EnableTelemetry";
+ var config = new SimpleTypedConfig(
+ key,
+ "Enable telemetry",
+ true);
+ var icm = GetConfigManager(config);
+ Assert.NotEmpty(icm.ListConfigs());
+ Assert.NotEmpty(icm.ListConfigs(null));
+ Assert.Empty(icm.ListConfigs(new ConfigFilter() { Keys = new string[] { "Never Exist" } }));
+ Assert.Empty(icm.ListConfigs(new ConfigFilter() { AppliesTo = "xxx" }));
+
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanGetAndListRegisteredConfigs()
+ {
+ const string key1 = "EnableTelemetry";
+ var config1 = new SimpleTypedConfig(
+ key1,
+ "Enable telemetry",
+ true);
+ TestConfig config2 = new TestConfig();
+ IConfigManager configurationManager = GetConfigManager(config1, config2);
+
+ var listResult = configurationManager.ListConfigs();
+ Assert.Equal(2, listResult.Count());
+
+ ConfigData configData = listResult.Where(x => x.Definition.Key == key1).Single();
+ Assert.Equal(true, configData.Value);
+ Assert.True(configurationManager.GetConfigValue(key1));
+
+ ConfigData tempConfigResult = listResult.Where(x => x.Definition.Key == config2.Key).Single();
+ Assert.Equal(config2.DefaultValue, tempConfigResult.Value);
+ Assert.Equal(config2.HelpMessage, tempConfigResult.Definition.HelpMessage);
+ Assert.Equal(config2.DefaultValue, configurationManager.GetConfigValue(config2.Key));
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanUpdateAndList()
+ {
+ IConfigManager configurationManager = GetConfigManager();
+ const string key = "EnableTelemetry";
+ configurationManager.RegisterConfig(
+ new SimpleTypedConfig(
+ key,
+ "Enable telemetry",
+ true));
+ configurationManager.BuildConfig();
+ var updatedConfig = configurationManager.UpdateConfig(new UpdateConfigOptions(key, false, ConfigScope.Process));
+ Assert.Equal(key, updatedConfig.Definition.Key);
+ Assert.False((bool)updatedConfig.Value);
+ Assert.False(configurationManager.GetConfigValue(key));
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanGetFromEnvironmentVar()
+ {
+ const string key = "FromEnv";
+ const string envKey = "ENV_VAR_FOR_CONFIG";
+ var config = new SimpleTypedConfig(key, "", -1, envKey);
+ const int value = 20;
+
+ var configurationManager = GetConfigManagerWithInitState(null, (envVar) => { envVar.Set(envKey, value.ToString()); }, config);
+
+ Assert.Equal(value, configurationManager.GetConfigValue(key));
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void ShouldNotThrowWhenEnvVarIsWrong()
+ {
+ const string key = "FromEnv";
+ const string envKey = "ENV_VAR_FOR_CONFIG";
+ const int defaultValue = -1;
+ var config = new SimpleTypedConfig(key, "", defaultValue, envKey);
+ const bool valueWithWrongType = true;
+ var configurationManager = GetConfigManagerWithInitState(null, envVar =>
+ {
+ envVar.Set(envKey, valueWithWrongType.ToString());
+ }, config);
+
+ Assert.Equal(defaultValue, configurationManager.GetConfigValue(key));
+ }
+
+ private class TestConfig : TypedConfig
+ {
+ public override object DefaultValue => -1;
+
+ public override string Key => "TempConfig";
+
+ public override string HelpMessage => "temp config";
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanGetFromJson()
+ {
+ var config1 = new SimpleTypedConfig("Retry", "", -1);
+ var config2 = new SimpleTypedConfig("Array", "", null);
+ IConfigManager icm = GetConfigManagerWithInitState((dataStore, path) =>
+ {
+ dataStore.WriteFile(path,
+@"{
+ ""Az"": {
+ ""Retry"": 100
+ },
+ ""Az.KeyVault"": {
+ ""Array"": [""a"",""b""]
+ },
+ ""Get-AzKeyVault"": {
+ ""Array"": [""k"",""v""]
+ }
+}");
+ }, null, config1, config2);
+ ConfigManager cm = icm as ConfigManager;
+ Assert.Equal(100, cm.GetConfigValue("Retry"));
+ Assert.Equal(new string[] { "a", "b" }, cm.GetConfigValueInternal("Array", new InternalInvocationInfo() { ModuleName = "Az.KeyVault" }));
+ Assert.Equal(new string[] { "k", "v" }, cm.GetConfigValueInternal("Array", new InternalInvocationInfo() { ModuleName = "Az.KeyVault", CmdletName = "Get-AzKeyVault" }));
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void ThrowWhenGetUnknownConfig()
+ {
+ IConfigManager entry = GetConfigManager();
+ entry.BuildConfig();
+
+ Assert.Throws(() => { entry.GetConfigValue(null); });
+ Assert.Throws(() => { entry.GetConfigValue(""); });
+
+ const string key = "KeyThatIsNotRegistered";
+ Assert.Throws(() => { entry.GetConfigValue(key); });
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanFilterByKeyAndAppliesTo()
+ {
+ const string key = "key";
+ var config = new SimpleTypedConfig(key, "", true);
+ var icm = GetConfigManager(config);
+ const string module = "Az.KeyVault";
+ icm.UpdateConfig(new UpdateConfigOptions(key, false, ConfigScope.CurrentUser) { AppliesTo = module });
+ Assert.Single(icm.ListConfigs(new ConfigFilter() { Keys = new[] { key }, AppliesTo = module }));
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanFilterByKey()
+ {
+ const string key = "key";
+ var config = new SimpleTypedConfig(key, "", true);
+ var icm = GetConfigManager(config);
+ const string module = "Az.KeyVault";
+ icm.UpdateConfig(new UpdateConfigOptions(key, false, ConfigScope.CurrentUser) { AppliesTo = module });
+ var listResults = icm.ListConfigs(new ConfigFilter() { Keys = new[] { key } });
+ Assert.Equal(2, listResults.Count());
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanFilterByAppliesTo()
+ {
+ const string key1 = "key";
+ var config1 = new SimpleTypedConfig(key1, "", true);
+ const string key2 = "key2";
+ var config2 = new SimpleTypedConfig(key2, "", true);
+ var icm = GetConfigManager(config1, config2);
+
+ const string module = "Az.KeyVault";
+ icm.UpdateConfig(new UpdateConfigOptions(key1, false, ConfigScope.CurrentUser) { AppliesTo = module });
+ icm.UpdateConfig(new UpdateConfigOptions(key2, false, ConfigScope.CurrentUser) { AppliesTo = module });
+
+ var listResults = icm.ListConfigs(new ConfigFilter() { AppliesTo = module });
+ Assert.Equal(2, listResults.Count());
+
+ listResults = icm.ListConfigs(new ConfigFilter() { AppliesTo = ConfigFilter.GlobalAppliesTo });
+ Assert.Equal(2, listResults.Count());
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanFilterByNoFilter()
+ {
+ const string key1 = "key";
+ var config1 = new SimpleTypedConfig(key1, "", true);
+ const string key2 = "key2";
+ var config2 = new SimpleTypedConfig(key2, "", true);
+ var icm = GetConfigManager(config1, config2);
+
+ const string module = "Az.KeyVault";
+ icm.UpdateConfig(new UpdateConfigOptions(key1, false, ConfigScope.CurrentUser) { AppliesTo = module });
+ icm.UpdateConfig(new UpdateConfigOptions(key2, false, ConfigScope.CurrentUser) { AppliesTo = module });
+ var listResults = icm.ListConfigs();
+ Assert.Equal(4, listResults.Count()); // default*2, module*2
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanListDefinitions()
+ {
+ const string key1 = "key";
+ var config1 = new SimpleTypedConfig(key1, "", true);
+ const string key2 = "key2";
+ var config2 = new SimpleTypedConfig(key2, "", true);
+ var config3 = new TestConfig();
+ var icm = GetConfigManager(config1, config2, config3);
+
+ Assert.Equal(3, icm.ListConfigDefinitions().Count());
+
+ const string module = "Az.KeyVault";
+ icm.UpdateConfig(new UpdateConfigOptions(key1, false, ConfigScope.CurrentUser) { AppliesTo = module });
+ Assert.Equal(3, icm.ListConfigDefinitions().Count());
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CanGetScope()
+ {
+ const string key1 = "key";
+ var config1 = new SimpleTypedConfig(key1, "", true);
+ var config2 = new TestConfig();
+ var icm = GetConfigManager(config1, config2);
+
+ var listResults = icm.ListConfigs();
+ foreach (var config in listResults)
+ {
+ Assert.Equal(ConfigScope.Default, config.Scope);
+ }
+
+ var updated = icm.UpdateConfig(new UpdateConfigOptions(key1, false, ConfigScope.CurrentUser));
+ Assert.Equal(ConfigScope.CurrentUser, updated.Scope);
+
+ updated = icm.UpdateConfig(new UpdateConfigOptions(key1, true, ConfigScope.Process));
+ Assert.Equal(ConfigScope.Process, updated.Scope);
+
+ icm.ClearConfig(new ClearConfigOptions(key1, ConfigScope.Process));
+ updated = icm.ListConfigs(new ConfigFilter() { Keys = new string[] { key1 } }).Single();
+ Assert.Equal(ConfigScope.CurrentUser, updated.Scope);
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void AppliesToShouldBeCaseInsensitive()
+ {
+ const string key = "key";
+ var config = new SimpleTypedConfig(key, "", 0);
+ var icm = GetConfigManager(config);
+
+ icm.UpdateConfig(new UpdateConfigOptions(key, 1, ConfigScope.CurrentUser) { AppliesTo = "az.abc" });
+ Assert.Equal(1, icm.ListConfigs(new ConfigFilter() { Keys = new[] { key }, AppliesTo = "az.abc" }).Single().Value);
+ Assert.Equal(1, icm.ListConfigs(new ConfigFilter() { Keys = new[] { key }, AppliesTo = "Az.Abc" }).Single().Value);
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void ListDefinitionsShouldBeDictOrder()
+ {
+ const string key1 = "key1";
+ var config1 = new SimpleTypedConfig(key1, "", 0);
+ const string key2 = "key2";
+ var config2 = new SimpleTypedConfig(key2, "", 0);
+ const string key3 = "key3";
+ var config3 = new SimpleTypedConfig(key3, "", 0);
+ // register using wrong order
+ var icm = GetConfigManager(config2, config1, config3);
+
+ for (int i = 0; i != 10; ++i)
+ {
+ var definitions = icm.ListConfigDefinitions();
+ // expect return with dict order
+ Assert.Equal(key1, definitions.ElementAt(0).Key);
+ Assert.Equal(key2, definitions.ElementAt(1).Key);
+ Assert.Equal(key3, definitions.ElementAt(2).Key);
+ }
+ }
+ }
+}
diff --git a/src/Accounts/Authentication.Test/ConfigTests/PriorityTests.cs b/src/Accounts/Authentication.Test/ConfigTests/PriorityTests.cs
new file mode 100644
index 000000000000..eb5972d0f571
--- /dev/null
+++ b/src/Accounts/Authentication.Test/ConfigTests/PriorityTests.cs
@@ -0,0 +1,85 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using Microsoft.Azure.Commands.Common.Authentication.Config;
+using Microsoft.Azure.PowerShell.Common.Config;
+using Microsoft.Rest.ClientRuntime.Azure.TestFramework;
+using Xunit;
+
+namespace Microsoft.Azure.Authentication.Test.Config
+{
+ public class PriorityTests : ConfigTestsBase
+ {
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void UserConfigHigherThanSystemUserEnv()
+ {
+ const string retryKey = "Retry";
+ const string envName = "ENV_FOR_RETRY";
+ var config = new SimpleTypedConfig(retryKey, "", -1, envName);
+ IConfigManager icm = GetConfigManagerWithInitState((dataStore, path) =>
+ {
+ dataStore.WriteFile(path,
+@"{
+ ""Az"": {
+ ""Retry"": 100
+ }
+}");
+ }, envVar =>
+ {
+ envVar.Set(envName, "10", System.EnvironmentVariableTarget.User);
+ }, config);
+ Assert.Equal(100, icm.GetConfigValue(retryKey));
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void ProcessEnvHigherThanUserConfig()
+ {
+
+ const string retryKey = "Retry";
+ const string envName = "ENV_FOR_RETRY";
+ var config = new SimpleTypedConfig(retryKey, "", -1, envName);
+ IConfigManager icm = GetConfigManagerWithInitState((dataStore, path) =>
+ {
+ dataStore.WriteFile(path,
+@"{
+ ""Az"": {
+ ""Retry"": 100
+ }
+}");
+ }, envVar =>
+ {
+ envVar.Set(envName, "10", System.EnvironmentVariableTarget.Process);
+ }, config);
+ Assert.Equal(10, icm.GetConfigValue(retryKey));
+ }
+
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void ProcessConfigHigherThanProcessEnv()
+ {
+ const string retryKey = "Retry";
+ const string envName = "ENV_FOR_RETRY";
+ var config = new SimpleTypedConfig(retryKey, "", -1, envName);
+ IConfigManager icm = GetConfigManagerWithInitState(null, envVar =>
+ {
+ envVar.Set(envName, "10", System.EnvironmentVariableTarget.Process);
+ }, config);
+
+ icm.UpdateConfig(new UpdateConfigOptions(retryKey, 100, ConfigScope.Process));
+ Assert.Equal(100, icm.GetConfigValue(retryKey));
+ }
+ }
+}
diff --git a/src/Accounts/Authentication.Test/ConfigTests/RegisterConfigTests.cs b/src/Accounts/Authentication.Test/ConfigTests/RegisterConfigTests.cs
new file mode 100644
index 000000000000..ec436c41afe5
--- /dev/null
+++ b/src/Accounts/Authentication.Test/ConfigTests/RegisterConfigTests.cs
@@ -0,0 +1,106 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using Microsoft.Azure.Commands.Common.Exceptions;
+using Microsoft.Azure.Commands.Common.Authentication.Config;
+using Microsoft.Azure.PowerShell.Common.Config;
+using Microsoft.Rest.ClientRuntime.Azure.TestFramework;
+using System;
+using System.Collections.Generic;
+using Xunit;
+
+namespace Microsoft.Azure.Authentication.Test.Config
+{
+ public class RegisterConfigTests : ConfigTestsBase
+ {
+ [Fact]
+ [Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
+ public void CannotRegisterSameKeyTwice()
+ {
+ IConfigManager entry = GetConfigManager();
+ const string key = "CannotRegisterTwice";
+ entry.RegisterConfig(new SimpleTypedConfig(key, "", -1));
+ Assert.Throws(() =>
+ {
+ entry.RegisterConfig(new SimpleTypedConfig