diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs
index 297bc10628..270e5c925e 100644
--- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs
+++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs
@@ -306,19 +306,19 @@ namespace System.Management.Automation
public enum XDG_Type
{
/// XDG_CONFIG_HOME/powershell
- CONFIG,
+ CONFIG = 0,
/// XDG_CACHE_HOME/powershell
- CACHE,
+ CACHE = 1,
/// XDG_DATA_HOME/powershell
- DATA,
+ DATA = 2,
/// XDG_DATA_HOME/powershell/Modules
- USER_MODULES,
+ USER_MODULES = 3,
/// /usr/local/share/powershell/Modules
- SHARED_MODULES,
- /// /etc/powershell
- SYSTEM_CONFIG,
+ SHARED_MODULES = 4,
/// XDG_CONFIG_HOME/powershell
- DEFAULT
+ DEFAULT = 5,
+ /// /etc/powershell
+ SYSTEM_CONFIG = 6,
}
///
diff --git a/src/System.Management.Automation/engine/PSConfiguration.cs b/src/System.Management.Automation/engine/PSConfiguration.cs
index caf2cc52b5..6c86d1470b 100644
--- a/src/System.Management.Automation/engine/PSConfiguration.cs
+++ b/src/System.Management.Automation/engine/PSConfiguration.cs
@@ -63,7 +63,6 @@ namespace System.Management.Automation.Configuration
// Legacy system-wide config file path in $PSHOME, used for fallback reads.
private readonly string legacySystemWideConfigFile;
- private bool systemConfigOverridden;
// The json file containing the per-user configuration settings.
private readonly string perUserConfigFile;
@@ -108,7 +107,9 @@ namespace System.Management.Automation.Configuration
fileLock = new ReaderWriterLockSlim();
}
- private string GetConfigFilePath(ConfigScope scope)
+ // Writes always target the new platform-specific location (systemWideConfigFile).
+ // Reads may fall back to the legacy $PSHOME location via GetEffectiveSystemWideConfigFile().
+ private string GetConfigFilePathForWrite(ConfigScope scope)
{
return (scope == ConfigScope.CurrentUser) ? perUserConfigFile : systemWideConfigFile;
}
@@ -120,11 +121,6 @@ namespace System.Management.Automation.Configuration
private string GetEffectiveSystemWideConfigFile()
{
- if (systemConfigOverridden)
- {
- return systemWideConfigFile;
- }
-
if (File.Exists(systemWideConfigFile))
{
return systemWideConfigFile;
@@ -138,7 +134,7 @@ namespace System.Management.Automation.Configuration
return systemWideConfigFile;
}
- internal string AllUsersConfigFilePath => systemWideConfigFile;
+ internal string AllUsersConfigFilePath => GetEffectiveSystemWideConfigFile();
internal string CurrentUserConfigFilePath => perUserConfigFile;
@@ -160,7 +156,6 @@ namespace System.Management.Automation.Configuration
FileInfo info = new FileInfo(value);
systemWideConfigFile = info.FullName;
systemWideConfigDirectory = info.Directory.FullName;
- systemConfigOverridden = true;
}
///
@@ -513,7 +508,7 @@ namespace System.Management.Automation.Configuration
{
try
{
- string fileName = GetConfigFilePath(scope);
+ string fileName = GetConfigFilePathForWrite(scope);
fileLock.EnterWriteLock();
// Since multiple properties can be in a single file, replacement is required instead of overwrite if a file already exists.
@@ -632,7 +627,7 @@ namespace System.Management.Automation.Configuration
/// The string key of the value.
private void RemoveValueFromFile(ConfigScope scope, string key)
{
- string fileName = GetConfigFilePath(scope);
+ string fileName = GetConfigFilePathForWrite(scope);
// Optimization: If the file doesn't exist, there is nothing to remove
if (File.Exists(fileName))
{
diff --git a/test/powershell/engine/ExperimentalFeature/EnableDisable-ExperimentalFeature.Tests.ps1 b/test/powershell/engine/ExperimentalFeature/EnableDisable-ExperimentalFeature.Tests.ps1
index 2258b321c3..d26bc41dd5 100644
--- a/test/powershell/engine/ExperimentalFeature/EnableDisable-ExperimentalFeature.Tests.ps1
+++ b/test/powershell/engine/ExperimentalFeature/EnableDisable-ExperimentalFeature.Tests.ps1
@@ -3,26 +3,6 @@
Import-Module HelpersCommon
-function Test-CanWriteToSystemConfigDir {
- $dir = Split-Path (Get-PowerShellConfiguration -Scope AllUsers).Path
- if (!(Test-Path $dir)) {
- try {
- $null = New-Item -ItemType Directory -Path $dir -Force -ErrorAction Stop
- return $true
- } catch {
- return $false
- }
- }
- try {
- $testFile = Join-Path $dir ".pester-write-test"
- Set-Content -Path $testFile -Value '' -ErrorAction Stop
- Remove-Item $testFile -Force -ErrorAction SilentlyContinue
- return $true
- } catch {
- return $false
- }
-}
-
Describe "Enable-ExperimentalFeature and Disable-ExperimentalFeature tests" -tags "Feature","RequireAdminOnWindows" {
BeforeAll {
diff --git a/test/powershell/engine/ExperimentalFeature/Get-ExperimentalFeature.Tests.ps1 b/test/powershell/engine/ExperimentalFeature/Get-ExperimentalFeature.Tests.ps1
index f3a39f312d..47ad3c8413 100644
--- a/test/powershell/engine/ExperimentalFeature/Get-ExperimentalFeature.Tests.ps1
+++ b/test/powershell/engine/ExperimentalFeature/Get-ExperimentalFeature.Tests.ps1
@@ -3,26 +3,6 @@
Import-Module HelpersCommon
-function Test-CanWriteToSystemConfigDir {
- $dir = Split-Path (Get-PowerShellConfiguration -Scope AllUsers).Path
- if (!(Test-Path $dir)) {
- try {
- $null = New-Item -ItemType Directory -Path $dir -Force -ErrorAction Stop
- return $true
- } catch {
- return $false
- }
- }
- try {
- $testFile = Join-Path $dir ".pester-write-test"
- Set-Content -Path $testFile -Value '' -ErrorAction Stop
- Remove-Item $testFile -Force -ErrorAction SilentlyContinue
- return $true
- } catch {
- return $false
- }
-}
-
Describe "Get-ExperimentalFeature Tests" -tags "Feature","RequireAdminOnWindows" {
BeforeAll {
diff --git a/test/powershell/engine/Help/HelpSystem.Tests.ps1 b/test/powershell/engine/Help/HelpSystem.Tests.ps1
index e7b36d2a67..0da509ab97 100644
--- a/test/powershell/engine/Help/HelpSystem.Tests.ps1
+++ b/test/powershell/engine/Help/HelpSystem.Tests.ps1
@@ -16,7 +16,7 @@ $script:cmdletsToSkip = @(
"Get-ExperimentalFeature",
"Enable-ExperimentalFeature",
"Disable-ExperimentalFeature",
- "Get-PowerShellConfiguration",
+ "Get-PowerShellConfiguration", # New cmdlet, help content pending
"Get-PSSubsystem",
"Switch-Process"
)
diff --git a/test/powershell/engine/PSConfiguration/Get-PowerShellConfiguration.Tests.ps1 b/test/powershell/engine/PSConfiguration/Get-PowerShellConfiguration.Tests.ps1
index 66e79dafe5..6f7bb5e408 100644
--- a/test/powershell/engine/PSConfiguration/Get-PowerShellConfiguration.Tests.ps1
+++ b/test/powershell/engine/PSConfiguration/Get-PowerShellConfiguration.Tests.ps1
@@ -22,13 +22,31 @@ Describe "Get-PowerShellConfiguration Tests" -Tags "CI" {
$config.Scope | Should -Be "CurrentUser"
}
- It "AllUsers path points to platform-specific system config directory" {
+ It "AllUsers path points to system config directory or legacy PSHOME location" {
$config = Get-PowerShellConfiguration -Scope AllUsers
+ $config.Path | Should -BeLike "*powershell.config.json"
if ($IsWindows) {
- $config.Path | Should -BeLike "*ProgramData*Microsoft*PowerShell*powershell.config.json"
+ $isNewPath = $config.Path -like "*ProgramData*Microsoft*PowerShell*"
+ $isLegacyPath = $config.Path -like "$PSHOME*"
+ ($isNewPath -or $isLegacyPath) | Should -BeTrue
}
else {
- $config.Path | Should -Be "/etc/powershell/powershell.config.json"
+ $isNewPath = $config.Path -eq "/etc/powershell/powershell.config.json"
+ $isLegacyPath = $config.Path -like "$PSHOME*"
+ ($isNewPath -or $isLegacyPath) | Should -BeTrue
+ }
+ }
+
+ It "AllUsers path prefers new location over PSHOME when config exists there" {
+ $config = Get-PowerShellConfiguration -Scope AllUsers
+ if ($IsWindows) {
+ $newPath = Join-Path $env:ProgramData "Microsoft\PowerShell\powershell.config.json"
+ }
+ else {
+ $newPath = "/etc/powershell/powershell.config.json"
+ }
+ if (Test-Path $newPath) {
+ $config.Path | Should -Be $newPath
}
}
@@ -45,11 +63,6 @@ Describe "Get-PowerShellConfiguration Tests" -Tags "CI" {
}
}
- It "AllUsers path does not point to PSHOME" {
- $config = Get-PowerShellConfiguration -Scope AllUsers
- $config.Path | Should -Not -BeLike "$PSHOME*"
- }
-
It "Output type is PowerShellConfigurationInfo" {
$config = Get-PowerShellConfiguration -Scope AllUsers
$config.GetType().Name | Should -Be "PowerShellConfigurationInfo"
diff --git a/test/tools/Modules/HelpersCommon/HelpersCommon.psd1 b/test/tools/Modules/HelpersCommon/HelpersCommon.psd1
index dd7cd7a52a..68ffdba913 100644
--- a/test/tools/Modules/HelpersCommon/HelpersCommon.psd1
+++ b/test/tools/Modules/HelpersCommon/HelpersCommon.psd1
@@ -29,6 +29,7 @@ FunctionsToExport = @(
'Set-TesthookResult'
'Start-NativeExecution'
'Test-CanWriteToPsHome'
+ 'Test-CanWriteToSystemConfigDir'
'Test-IsElevated'
'Test-IsPreview',
'Test-IsReleaseCandidate'
diff --git a/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 b/test/tools/Modules/HelpersCommon/HelpersCommon.psm1
index 02588b612d..f90b275bba 100644
--- a/test/tools/Modules/HelpersCommon/HelpersCommon.psm1
+++ b/test/tools/Modules/HelpersCommon/HelpersCommon.psm1
@@ -345,6 +345,37 @@ function Test-CanWriteToPsHome
$script:CanWriteToPsHome
}
+$script:CanWriteToSystemConfigDir = $null
+function Test-CanWriteToSystemConfigDir {
+ [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingEmptyCatchBlock', '', Justification = "an error message is not appropriate for this function")]
+ param ()
+ if ($null -ne $script:CanWriteToSystemConfigDir) {
+ return $script:CanWriteToSystemConfigDir
+ }
+
+ $script:CanWriteToSystemConfigDir = $false
+ $dir = Split-Path (Get-PowerShellConfiguration -Scope AllUsers).Path
+ if (!(Test-Path $dir)) {
+ try {
+ $null = New-Item -ItemType Directory -Path $dir -Force -ErrorAction Stop
+ $script:CanWriteToSystemConfigDir = $true
+ } catch {
+ ; # do nothing
+ }
+ } else {
+ try {
+ $testFile = Join-Path $dir ".pester-write-test"
+ Set-Content -Path $testFile -Value '' -ErrorAction Stop
+ Remove-Item $testFile -Force -ErrorAction SilentlyContinue
+ $script:CanWriteToSystemConfigDir = $true
+ } catch {
+ ; # do nothing
+ }
+ }
+
+ $script:CanWriteToSystemConfigDir
+}
+
# Creates a password meeting Windows complexity rules
function New-ComplexPassword
{
diff --git a/test/xUnit/csharp/test_PSConfiguration.cs b/test/xUnit/csharp/test_PSConfiguration.cs
index 6451c8c71b..8dbbef4913 100644
--- a/test/xUnit/csharp/test_PSConfiguration.cs
+++ b/test/xUnit/csharp/test_PSConfiguration.cs
@@ -34,6 +34,7 @@ namespace PSTests.Sequential
private readonly PowerShellPolicies currentUserPolicies;
private readonly bool originalTestHookValue;
+ private readonly string originalTestAllUsersConfigDirectory;
private readonly string originalSingletonSystemConfigDir;
private readonly string originalSingletonSystemConfigFile;
@@ -43,6 +44,7 @@ namespace PSTests.Sequential
// to /etc/powershell (Unix) or %ProgramData%\Microsoft\PowerShell (Windows) in CI
systemWideConfigDirectory = Path.Combine(Path.GetTempPath(), "PSTestSystemConfig_" + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(systemWideConfigDirectory);
+ originalTestAllUsersConfigDirectory = InternalTestHooks.TestAllUsersConfigDirectory;
InternalTestHooks.TestAllUsersConfigDirectory = systemWideConfigDirectory;
currentUserConfigDirectory = Platform.UserConfigDirectory;
@@ -58,12 +60,10 @@ namespace PSTests.Sequential
// Redirect the PowerShellConfig singleton to use the temp system config directory
var sysConfigDirField = typeof(PowerShellConfig).GetField("systemWideConfigDirectory", BindingFlags.NonPublic | BindingFlags.Instance);
var sysConfigFileField = typeof(PowerShellConfig).GetField("systemWideConfigFile", BindingFlags.NonPublic | BindingFlags.Instance);
- var overriddenField = typeof(PowerShellConfig).GetField("systemConfigOverridden", BindingFlags.NonPublic | BindingFlags.Instance);
originalSingletonSystemConfigDir = (string)sysConfigDirField.GetValue(PowerShellConfig.Instance);
originalSingletonSystemConfigFile = (string)sysConfigFileField.GetValue(PowerShellConfig.Instance);
sysConfigDirField.SetValue(PowerShellConfig.Instance, systemWideConfigDirectory);
sysConfigFileField.SetValue(PowerShellConfig.Instance, systemWideConfigFile);
- overriddenField.SetValue(PowerShellConfig.Instance, true);
if (File.Exists(currentUserConfigFile))
{
@@ -124,11 +124,9 @@ namespace PSTests.Sequential
// Restore the PowerShellConfig singleton to the original system config paths
var sysConfigDirField = typeof(PowerShellConfig).GetField("systemWideConfigDirectory", BindingFlags.NonPublic | BindingFlags.Instance);
var sysConfigFileField = typeof(PowerShellConfig).GetField("systemWideConfigFile", BindingFlags.NonPublic | BindingFlags.Instance);
- var overriddenField = typeof(PowerShellConfig).GetField("systemConfigOverridden", BindingFlags.NonPublic | BindingFlags.Instance);
sysConfigDirField.SetValue(PowerShellConfig.Instance, originalSingletonSystemConfigDir);
sysConfigFileField.SetValue(PowerShellConfig.Instance, originalSingletonSystemConfigFile);
- overriddenField.SetValue(PowerShellConfig.Instance, false);
- InternalTestHooks.TestAllUsersConfigDirectory = null;
+ InternalTestHooks.TestAllUsersConfigDirectory = originalTestAllUsersConfigDirectory;
if (Directory.Exists(systemWideConfigDirectory))
{